589 lines
18 KiB
Plaintext
589 lines
18 KiB
Plaintext
// Weather Station 3 from AliExpress / TaoBao
|
|
//
|
|
// Highly inspired by https://github.com/kquinsland/ws3-to-esphome-bridge/
|
|
//
|
|
// Maybe the code is not optimal but it works.
|
|
//
|
|
// Configuration of WS3 :
|
|
//
|
|
// JP1 toggle betwen ARS inch mode and professional metric mode
|
|
// short : inch
|
|
// open : metric
|
|
//
|
|
// JP2 baud rate
|
|
// short : 2400
|
|
// open : 9600
|
|
//
|
|
// Configuration used for this code :
|
|
// JP1 : open
|
|
// JP2 : closed
|
|
//
|
|
// Data is in the form :
|
|
//
|
|
// A4095B000C0000D0000E0000F0000G0000H0000I0000J0000K0000L0218M515N09654O.....*52
|
|
//
|
|
//
|
|
// Serial connection used there (hardcoded using AltSoftSerial) :
|
|
// Only TX has to be connected, RX is not used by WS3.
|
|
//
|
|
// Board Receive
|
|
// ----- -------
|
|
// Teensy 3.0 & 3.1 20
|
|
// Teensy 2.0 10
|
|
// Teensy++ 2.0 4
|
|
// Arduino Uno 8
|
|
// EtherTen 8
|
|
// Arduino Leonardo 13
|
|
// Arduino Mega 48
|
|
// Wiring-S 6
|
|
// Sanguino 14
|
|
//
|
|
// This code was tested and developped on EtherTen board which
|
|
// is Arduino Uno compatible with some additions.
|
|
//
|
|
// Use following libraries:
|
|
// - AltSoftSerial
|
|
// - Adafruit_MQTT
|
|
//
|
|
#include <ESP8266WiFi.h>
|
|
#include <AddrList.h>
|
|
// EspSoftwareSerial (or plain SoftwareSerial)
|
|
#include <SoftwareSerial.h>
|
|
// MQTT
|
|
#include <PubSubClient.h>
|
|
|
|
// Domoticz MQTT configuration
|
|
const char* mqtt_server = "portbuild.home.oav.net";
|
|
#define mqtt_port 1883
|
|
// Domoticz Indexes (virtual devices has to be created)
|
|
#define domoticz_windir 48 // Wind Virtual device
|
|
#define domoticz_temp 52 // Temp / Him / Baro virtual device
|
|
#define domoticz_rain 51 // Rain Virtual device
|
|
#define ELEVATION 323 // Elevation from the place we are
|
|
// Longwy is at 323m
|
|
|
|
// Definitions
|
|
const char* Mqtt_clientid = "ESP-Weather-Station";
|
|
const char* dom_in = "domoticz/in";
|
|
#define MQTT_MAX_PACKET_SIZE 128
|
|
char msgToPublish[MQTT_MAX_PACKET_SIZE + 1];
|
|
|
|
// Wifi
|
|
const char* ssid = "Kiwi";
|
|
const char* password = "ZeKiwi127";
|
|
|
|
// Defines
|
|
#define DEBUG 1
|
|
|
|
#ifdef DEBUG
|
|
#define debug(x) Serial.print(x)
|
|
#define debugln(x) Serial.println(x)
|
|
#else /* DEBUG */
|
|
#define debug(x)
|
|
#define debugln(x)
|
|
#endif /* DEBUG */
|
|
// Baud used to read see JP2
|
|
#define WS3_BAUD 2400
|
|
// Toggle support for PM2.5 sensor
|
|
//#define SUPPORT_PM25_SENSOR
|
|
|
|
// Define the length of data
|
|
#ifdef SUPPORT_PM25_SENSOR
|
|
// There is 88 bytes per packets
|
|
#define WS3_PKT_LEN 78
|
|
// And the checksum is the last 2 bytes
|
|
#define WS3_CHK_LEN 2
|
|
#define CHK_SUM_DELINEATOR 75
|
|
#else /* SUPPORT_PM25_SENSOR */
|
|
// There is 88 bytes per packets
|
|
#define WS3_PKT_LEN 78
|
|
// And the checksum is the last 2 bytes
|
|
#define WS3_CHK_LEN 2
|
|
#define CHK_SUM_DELINEATOR 75
|
|
#endif /* SUPPRT_PM25_SENSOR */
|
|
|
|
// Seems the Metric format does not have a correct checksum
|
|
// In this case we should not test the checksum, just see
|
|
// if we have a correct dataline
|
|
#define DONT_CHKSUM 1
|
|
|
|
// Place holder for the packet received
|
|
String pkt_str = "";
|
|
|
|
// Flag for packet OK
|
|
volatile byte pkt_ok = false;
|
|
|
|
SoftwareSerial WS3(15,16);
|
|
WiFiClient espClient;
|
|
PubSubClient client(espClient);
|
|
|
|
// After parsing the string of bytes, we'll have an easier to use struct
|
|
// TODO: this should be it's own file?
|
|
struct WS3Packet {
|
|
|
|
// The 1st field is "A0000" - Wind direction AD value in real time (0-4096)
|
|
unsigned int wind_dir;
|
|
// The 2nd field is "B000" - Wind direct angle value (16 direction)
|
|
unsigned int wind_angle; // new
|
|
// The 3rd field is "C0000" - Real time wind speed frequency 1Hz
|
|
unsigned int wind_freq; // New
|
|
// The 4th field is "D0000" - Real time wind speed, unit: 0.1 m/s
|
|
float wind_speed;
|
|
// The 5th field is "E0000" - Avg wind speed in the previous minute, unit: 0.1m/s
|
|
float wind_speed_1m;
|
|
// The 6th field is "F0000" - the highest wind speed in the last 5 minutes, unit: 0.1m/s
|
|
float wind_speed_5m;
|
|
// The 7th field is "G0000" - Real time rain bucket (0-9999), loop-count
|
|
int rain_bucket_cnt; // New
|
|
// The 8th field is "H0000" - Number of rain bucket in the last minute, (0-9999)
|
|
int rt_rain_bucket;
|
|
// The 9th field is "I0000" - Rain fall in 1 minute, unit: 0.1mm
|
|
float rain_1m;
|
|
// The 10th field is "J0000" - the previous hour's rainfall ( 0.1 mm)
|
|
float rain_1h;
|
|
// The 11th field is "K0000" - rainfall during the first 24 hours ( 0.1 mm)
|
|
float rain_24h;
|
|
// The 12th field is "L0000" - temperature, unit: degree C (unit 0.1 Degree)
|
|
float temp_f;
|
|
// The 13th field is "M000" - humidity ( 00 % - 99 %), unit 0.1%
|
|
float humidity;
|
|
// The 14th field is "M10020" - air pressure ( 0.1 hpa )
|
|
float air_pressure;
|
|
};
|
|
|
|
// Return the index according to Wind Angle
|
|
String str_windir(unsigned int WinVal){
|
|
//debug("str_windir() : ");
|
|
//debugln(WinVal);
|
|
if(WinVal >= 360) return "N"; //N
|
|
if(WinVal >= 0 && WinVal < 22) return "N"; //N
|
|
if(WinVal >= 22 && WinVal < 45) return "NNE"; //NNE
|
|
if(WinVal >= 45 && WinVal < 67) return "NE"; //NE
|
|
if(WinVal >= 67 && WinVal < 90) return "ENE"; //ENE
|
|
if(WinVal >= 90 && WinVal < 112) return "E"; //E
|
|
if(WinVal >= 112 && WinVal < 135) return "ESE"; //ESE
|
|
if(WinVal >= 135 && WinVal < 157) return "SE"; //SE
|
|
if(WinVal >= 157 && WinVal < 180) return "S"; //S
|
|
if(WinVal >= 180 && WinVal < 202) return "S"; //S
|
|
if(WinVal >= 202 && WinVal < 225) return "SSW"; //SSW
|
|
if(WinVal >= 225 && WinVal < 247) return "SW"; //SW
|
|
if(WinVal >= 247 && WinVal < 270) return "WSW"; //WSW
|
|
if(WinVal >= 270 && WinVal < 292) return "W"; //W
|
|
if(WinVal >= 292 && WinVal < 315) return "WNW"; //WNW
|
|
if(WinVal >= 315 && WinVal < 337) return "NW"; //NW
|
|
if(WinVal >= 337 && WinVal < 359) return "NNW"; //NNW
|
|
}
|
|
|
|
// Setup the stuff.
|
|
void setup() {
|
|
//Serial.begin(460800);
|
|
Serial.begin(57600);
|
|
while (!Serial) ; // wait for Arduino Serial Monitor to open
|
|
Serial.println("");
|
|
Serial.println("Weather Station 3 Adapter by Kiwi");
|
|
Serial.println(ESP.getFullVersion());
|
|
|
|
WiFi.hostname("ESP-Weather-Station");
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.begin(ssid, password);
|
|
|
|
// Use this loop instead to wait for an IPv6 routable address
|
|
|
|
// addr->isLocal() (meaning "not routable on internet") is true with:
|
|
// - IPV4 DHCP autoconfigured address 169.254.x.x
|
|
// (false for any other including 192.168./16 and 10./24 since NAT may be in the equation)
|
|
// - IPV6 link-local addresses (fe80::/64)
|
|
|
|
for (bool configured = false; !configured;) {
|
|
for (auto addr : addrList)
|
|
if ((configured = !addr.isLocal()
|
|
// && addr.isV6() // uncomment when IPv6 is mandatory
|
|
// && addr.ifnumber() == STATION_IF
|
|
)) {
|
|
break;
|
|
}
|
|
Serial.print('.');
|
|
delay(500);
|
|
}
|
|
Serial.println("");
|
|
Serial.println(F("WiFi Connected !"));
|
|
#if LWIP_IPV6
|
|
Serial.printf("IPV6 is enabled\n");
|
|
#else
|
|
Serial.printf("IPV6 is not enabled\n");
|
|
#endif
|
|
Serial.print("My IP address: ");
|
|
Serial.println(WiFi.localIP());
|
|
// TODO: Find the IPv6 given to the ESP ?
|
|
|
|
|
|
// Start the Software Serial for WS3
|
|
WS3.begin(WS3_BAUD);
|
|
debugln("WS3 UART is ready...");
|
|
|
|
// Allocate memory for packet
|
|
pkt_str.reserve(WS3_PKT_LEN);
|
|
debugln(" -> Packet memory allocated!");
|
|
|
|
// Now connect to MQTT
|
|
client.setServer(mqtt_server, mqtt_port);
|
|
//client.setCallback(callback);
|
|
debugln("MQTT started");
|
|
}
|
|
|
|
#ifdef DONT_CHKSUM
|
|
// Validate packet using the checksum.
|
|
// Work only APRS data on this 51W3 board.
|
|
// Maybe the code on the board does not make the correct checksum ?
|
|
bool validate_packet(String pay, unsigned long chk) {
|
|
// Print the payload and the checksum we want
|
|
debugln("validate_packet:");
|
|
debug(pay);
|
|
debug(" * ");
|
|
debugln(chk);
|
|
|
|
// TEST DATA (actual packets)
|
|
// c000s000g000t075r000p019h43b09940*32
|
|
// String pay = "c000s000g000t075r000p019h43b09940";
|
|
// byte chk = 0x32; // this will be in HEX)
|
|
|
|
// c000s000g000t075r000p019h42b09940*33
|
|
// String pay = "c000s000g000t075r000p019h42b09940";
|
|
// byte chk = 0x33; // this will be in HEX)
|
|
|
|
// c000s000g000t075r000p019h42b09939*3D
|
|
// String pay = "c000s000g000t075r000p019h42b09939";
|
|
// byte chk = 0x3D; // this will be in HEX)
|
|
|
|
// SUPER grateful for the helpful https://toolslick.com/math/bitwise/xor-calculator to validate my
|
|
// code!
|
|
|
|
// Current byte
|
|
byte i1=0;
|
|
|
|
// the intermediate checksum
|
|
byte tmp = 0;
|
|
|
|
// starting from the second character, we begin XORing
|
|
for (int x = 0; x < pay.length() ; x++) {
|
|
|
|
i1=pay[x];
|
|
|
|
// Do the xOR
|
|
tmp = tmp^i1;
|
|
|
|
}
|
|
|
|
// do the check
|
|
if(tmp == chk){
|
|
return true;
|
|
} else {
|
|
debugln("INVALID!");
|
|
debug("calculated:");
|
|
debugln(tmp);
|
|
return false;
|
|
}
|
|
}
|
|
#endif /* DONT_CHKSUM */
|
|
|
|
|
|
// Parse the packet and fill the structure with data
|
|
void parse_packet(String payload, WS3Packet* p) {
|
|
|
|
// E.G.: A4095 B000 C0000 D0000 E0000 F0000 G0000 H0000 I0000 J0000 K0000 L0237 M502 N09810 O.....
|
|
|
|
// Parse in order, starting with A0000 (wind dir real time, 0-4096)
|
|
int wind_dir_idx = payload.indexOf('A');
|
|
p->wind_dir = payload.substring(wind_dir_idx+1, wind_dir_idx+5).toInt();
|
|
|
|
// Then move on to B000 - wind direction angle (16 direction)
|
|
int wind_angle_idx = payload.indexOf('B');
|
|
p->wind_angle = payload.substring(wind_angle_idx+1, wind_angle_idx+4).toInt();
|
|
|
|
// Then move on to C0000 - wind speed frequency (1 Hz)
|
|
int wind_freq_idx = payload.indexOf('C');
|
|
p->wind_freq = payload.substring(wind_freq_idx+1, wind_freq_idx+5).toInt();
|
|
|
|
// Then move on to D0000 - wind speed real time (unit 0.1 m/s)
|
|
int wind_speed_idx = payload.indexOf('D');
|
|
p->wind_speed = payload.substring(wind_speed_idx+1, wind_speed_idx+5).toInt() / 10;
|
|
|
|
// Then move on to E0000 - wind speed avg in the last minute (unit 0.1 m/s)
|
|
int wind_speed_1m_idx = payload.indexOf('D');
|
|
p->wind_speed_1m = payload.substring(wind_speed_1m_idx+1, wind_speed_1m_idx+5).toInt() / 10;
|
|
|
|
// Then move on to F0000 - wind speed over the last 5 min
|
|
int wind_speed_5_idx = payload.indexOf('F');
|
|
p->wind_speed_5m = payload.substring(wind_speed_5_idx+1, wind_speed_5_idx+5).toInt() / 10;
|
|
|
|
// Then move on to G0000 - Rain in Realtime (0-9999 counter) bucket
|
|
int rain_bucket_cnt_idx = payload.indexOf('G');
|
|
p->rain_bucket_cnt = payload.substring(rain_bucket_cnt_idx+1, rain_bucket_cnt_idx+5).toInt();
|
|
|
|
// Then move on to H0000 - Rain bucket in the last 1 minute (0-9999 counter)
|
|
int rt_rain_bucket_idx = payload.indexOf('H');
|
|
p->rt_rain_bucket = payload.substring(rt_rain_bucket_idx+1, rt_rain_bucket_idx+5).toInt();
|
|
|
|
// Then move on to I0000 - rain last minute (0.1mm)
|
|
int rain1m_idx = payload.indexOf('I');
|
|
p->rain_1m = payload.substring(rain1m_idx+1, rain1m_idx+5).toInt() *.1;
|
|
|
|
// Then move on to J0000 - rain last hour (0.1mm)
|
|
int rain1h_idx = payload.indexOf('J');
|
|
p->rain_1h = payload.substring(rain1h_idx+1, rain1h_idx+5).toInt() *.1;
|
|
|
|
// Then move on to K0000 - rain last 24h (0.1mm)
|
|
int rain24h_idx = payload.indexOf('K');
|
|
p->rain_24h = payload.substring(rain24h_idx+1, rain24h_idx+5).toInt()*.1;
|
|
|
|
// Then move on to L0200 - temp (0.1°C)
|
|
// XXX: Check with minus zero temperatures
|
|
int temp_idx = payload.indexOf('L');
|
|
p->temp_f = payload.substring(temp_idx+1, temp_idx+5).toInt()*.1;
|
|
|
|
// Then move on to M611 - Humidity
|
|
int humidity_idx = payload.indexOf('M');
|
|
// p->humidity = payload.substring(humidity_idx+1, humidity_idx+3).toInt()*.1;
|
|
p->humidity = payload.substring(humidity_idx+1, humidity_idx+3).toInt();
|
|
|
|
// Then move on to N10020 - air pressure
|
|
int pressure_idx = payload.indexOf('N');
|
|
p->air_pressure = payload.substring(pressure_idx+1, pressure_idx+6).toInt()*.1;
|
|
|
|
}
|
|
|
|
// Clear the packet before working on the next
|
|
void clear_pkt(WS3Packet* p) {
|
|
p->wind_dir = 0;
|
|
p->wind_angle = 0;
|
|
p->wind_freq = 0;
|
|
p->wind_speed = 0;
|
|
p->wind_speed_1m = 0;
|
|
p->wind_speed_5m = 0;
|
|
p->rain_bucket_cnt = 0;
|
|
p->rt_rain_bucket = 0;
|
|
p->rain_1m = 0;
|
|
p->rain_1h = 0;
|
|
p->rain_24h = 0;
|
|
p->temp_f = 0;
|
|
p->humidity = 0;
|
|
p->air_pressure = 0;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// Print the data
|
|
void print_weather(WS3Packet* p){
|
|
Serial.print("Wind Direction (realtime): ");
|
|
Serial.println(p->wind_dir, DEC);
|
|
//Serial.println(" degrees");
|
|
Serial.print("Wind direction angle : ");
|
|
Serial.print(p->wind_angle, DEC);
|
|
Serial.print(" degree ");
|
|
Serial.println(str_windir(p->wind_angle));
|
|
Serial.print("Wind speed Frequency: ");
|
|
Serial.print(p->wind_freq, DEC);
|
|
Serial.println(" Hz");
|
|
Serial.print("Wind speed: ");
|
|
Serial.print(p->wind_speed, DEC);
|
|
Serial.println(" m/s");
|
|
Serial.print("Wind speed 1m: ");
|
|
Serial.print(p->wind_speed_1m, DEC);
|
|
Serial.println(" m/s");
|
|
Serial.print("Wind speed 5m: ");
|
|
Serial.print(p->wind_speed_5m, DEC);
|
|
Serial.println(" m/s");
|
|
Serial.print("temp_f: ");
|
|
Serial.print(p->temp_f, DEC);
|
|
Serial.println(" deg. C.");
|
|
|
|
Serial.print("Rain buckets / buckets 1m: ");
|
|
Serial.print(p->rain_bucket_cnt, DEC);
|
|
Serial.print(" / ");
|
|
Serial.println(p->rt_rain_bucket, DEC);
|
|
|
|
Serial.print("Rain 1m / 1H / 24H: ");
|
|
Serial.print(p->rain_1m, DEC);
|
|
Serial.print(" / ");
|
|
Serial.print(p->rain_1h, DEC);
|
|
Serial.print(" / ");
|
|
Serial.print(p->rain_24h, DEC);
|
|
Serial.println(" mm");
|
|
|
|
Serial.print("humidity: ");
|
|
Serial.print(p->humidity, DEC);
|
|
Serial.println(" %");
|
|
|
|
Serial.print("air_pressure: ");
|
|
Serial.print(p->air_pressure, DEC);
|
|
Serial.println(" hpa");
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
// Print the data over MQTT
|
|
void push_weather(WS3Packet* p) {
|
|
String MQPayload;
|
|
float SLpressure_mB;
|
|
float WindGust = 0.0; // Gust is actually set to 0.0
|
|
// Have to find a nice way to compute this.
|
|
// Rain
|
|
MQPayload = "{ \"idx\" : "+ String(domoticz_rain) +",\"nvalue\" : 0, \"svalue\" : \"" + String(p->rain_1m) + ";" + String(p->rain_1m) + "\"}";
|
|
sendMQTTPayload(MQPayload);
|
|
// Temperature / Humidity / Baro
|
|
//SLpressure_mB = (((p->air_pressure)/pow((1-((float)(ELEVATION))/44330), 5.255))/100.0);
|
|
SLpressure_mB = p->air_pressure;
|
|
MQPayload = "{ \"idx\" : "+ String(domoticz_temp) +",\"nvalue\" : 0, \"svalue\": \"" + String(p->temp_f) + ";" + String(p->humidity) + ";0;" + String(SLpressure_mB) +";0\"}";
|
|
sendMQTTPayload(MQPayload);
|
|
// Wind
|
|
MQPayload = "{ \"idx\" : "+ String(domoticz_windir) +",\"nvalue\" : 0, \"svalue\": \"" + String(p->wind_angle) + ";" + String(str_windir(p->wind_angle)) + ";" + String(p->wind_speed*10) + ";" + String(WindGust*10) +";" + String(p->temp_f) + ";"+String(p->temp_f)+"\"}";
|
|
sendMQTTPayload(MQPayload);
|
|
}
|
|
|
|
|
|
// Processing the packet.
|
|
bool process_packet(String pkt, WS3Packet* p) {
|
|
debugln("[D] process_packet - ALive!");
|
|
debugln(pkt);
|
|
|
|
// Allocate bytes for the payload
|
|
String payload;
|
|
payload.reserve(WS3_PKT_LEN-WS3_CHK_LEN);
|
|
|
|
#ifdef DONT_CHKSUM
|
|
// everything after the * is checksum (2 char long)
|
|
unsigned long chksum;
|
|
#endif /* DONT_CHKSUM */
|
|
|
|
// Check if the 75rd character is *
|
|
if (pkt.charAt(CHK_SUM_DELINEATOR) != '*') {
|
|
debugln("Packed invalid; no * character at position 75!");
|
|
return false;
|
|
#ifdef DONT_CHKSUM
|
|
} else {
|
|
// The character indicating the checksum is coming is in the correct place. Yay.
|
|
// Now, we need to pull the two ascii characters that are transmitted to us
|
|
// and turn them into a single byte. E.G. Char 3, Char D should convert to 0x3D.
|
|
//
|
|
// We can do this with the strtoul() function; we indicate that we wante base 16
|
|
|
|
chksum = strtoul(pkt.substring(CHK_SUM_DELINEATOR+1, CHK_SUM_DELINEATOR+2).c_str(),NULL,16);
|
|
}
|
|
#endif /* DONT_CHKSUM */
|
|
|
|
// We have the checksum, Now we can bother to get the payload
|
|
payload = pkt.substring(0, CHK_SUM_DELINEATOR);
|
|
|
|
// And try to validate...
|
|
#ifndef DONT_CHKSUM
|
|
if(!validate_packet(payload, chksum)){
|
|
debugln("invalid packet! :(");
|
|
return false;
|
|
} else {
|
|
debugln("Valid packet!");
|
|
}
|
|
#endif /* DONT_CHKSUM */
|
|
parse_packet(payload, p);
|
|
return true;
|
|
}
|
|
|
|
void loop() {
|
|
// MQTT
|
|
if (!client.connected()) {
|
|
reconnect();
|
|
}
|
|
// While data comes in and we don't have a pending packet to process...
|
|
while (WS3.available() && pkt_ok !=true) {
|
|
|
|
// Pull the bytes off the stream
|
|
char inChar = (char)WS3.read();
|
|
|
|
// And build up the packet
|
|
pkt_str += inChar;
|
|
|
|
// Until we hit the end
|
|
if (inChar == '\n') {
|
|
pkt_ok = true;
|
|
}
|
|
}
|
|
|
|
// Yay, we now have a packet!
|
|
// Now, we attempt to parse out the string into a packet that we can work with
|
|
if (pkt_ok) {
|
|
debugln("pkt_ok!");
|
|
|
|
// At this point, we have a string of characters that was probably a valid packet
|
|
// We set get some memory and attempt to parse the string into the struct
|
|
WS3Packet p = {};
|
|
|
|
// Validate the payload, then parse it.
|
|
if (process_packet(pkt_str, &p)) {
|
|
// print results if parse OK
|
|
#ifdef DEBUG
|
|
print_weather(&p);
|
|
#endif /* DEBUG */
|
|
push_weather(&p);
|
|
debugln("processed");
|
|
} else {
|
|
debugln("unable to parse packet :(");
|
|
}
|
|
|
|
|
|
// clear so we can start again
|
|
pkt_str = "";
|
|
pkt_ok = false;
|
|
clear_pkt(&p);
|
|
}
|
|
}
|
|
|
|
// MQTT Stuff
|
|
void callback(char* topic, byte* payload, unsigned int length) {
|
|
debug("Message arrived [");
|
|
Serial.print(topic);
|
|
debug("] ");
|
|
for (int i = 0; i < length; i++) {
|
|
Serial.print((char)payload[i]);
|
|
}
|
|
debug(" ");
|
|
}
|
|
void reconnect() {
|
|
// Loop until we're reconnected
|
|
while (!client.connected()) {
|
|
debug("Attempting MQTT connection...");
|
|
// Attempt to connect
|
|
if (client.connect(Mqtt_clientid)) {
|
|
debugln("connected");
|
|
// ... and resubscribe
|
|
client.subscribe(dom_in);
|
|
} else {
|
|
debug("failed, rc=");
|
|
debug(client.state());
|
|
debugln(" try again in 5 seconds");
|
|
// Wait 5 seconds before retrying
|
|
for(int i = 0; i<5000; i++){
|
|
delay(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sends MQTT payload to the Mosquitto server running on a Raspberry Pi.
|
|
// Mosquitto server deliveres data to Domoticz server running on a same Raspberry Pi
|
|
void sendMQTTPayload(String msgpayload)
|
|
{
|
|
// Convert payload to char array
|
|
msgpayload.toCharArray(msgToPublish, msgpayload.length()+1);
|
|
|
|
//Publish payload to MQTT broker
|
|
if (client.publish(dom_in, msgToPublish))
|
|
{
|
|
debug("Following data published to MQTT broker: ");
|
|
debug(dom_in);
|
|
debug(" ");
|
|
debugln(msgpayload);
|
|
}
|
|
else
|
|
{
|
|
debug("Publishing to MQTT broker failed... ");
|
|
debugln(client.state());
|
|
}
|
|
}
|