diff --git a/kicad/lghp-slave/lghp-slave.sch b/kicad/lghp-slave/lghp-slave.sch --- a/kicad/lghp-slave/lghp-slave.sch +++ b/kicad/lghp-slave/lghp-slave.sch @@ -1,299 +1,299 @@ EESchema Schematic File Version 4 EELAYER 30 0 EELAYER END $Descr A4 11693 8268 encoding utf-8 Sheet 1 1 Title "" Date "" Rev "" Comp "" Comment1 "" Comment2 "" Comment3 "" Comment4 "" $EndDescr $Comp L ESP8266:NodeMCU_1.0_(ESP-12E) U3 U 1 1 61401A4F P 6200 2700 F 0 "U3" H 6200 3787 60 0000 C CNN F 1 "NodeMCU_1.0_(ESP-12E)" H 6200 3681 60 0000 C CNN F 2 "ESP8266:NodeMCU3.0(12-E)-Corrected" H 5600 1850 60 0001 C CNN F 3 "" H 5600 1850 60 0000 C CNN 1 6200 2700 1 0 0 -1 $EndComp $Comp L Isolator:6N139 U1 U 1 1 61402196 P 3750 2000 F 0 "U1" H 3750 2467 50 0000 C CNN F 1 "6N139_RX" H 3750 2376 50 0000 C CNN F 2 "Package_DIP:DIP-8_W7.62mm" H 4040 1700 50 0001 C CNN F 3 "http://www.onsemi.com/pub/Collateral/HCPL2731-D.pdf" H 4040 1700 50 0001 C CNN 1 3750 2000 1 0 0 -1 $EndComp $Comp L Isolator:6N139 U2 U 1 1 6140323D P 3750 3150 F 0 "U2" H 3750 3617 50 0000 C CNN F 1 "6N139_TX" H 3750 3526 50 0000 C CNN F 2 "Package_DIP:DIP-8_W7.62mm" H 4040 2850 50 0001 C CNN F 3 "http://www.onsemi.com/pub/Collateral/HCPL2731-D.pdf" H 4040 2850 50 0001 C CNN 1 3750 3150 1 0 0 -1 $EndComp $Comp L Connector_Generic_MountingPin:Conn_01x04_MountingPin J2 U 1 1 61404B60 P 8250 2200 F 0 "J2" H 8338 2114 50 0000 L CNN F 1 "5V_BUCK_CONVERTER" H 8338 2023 50 0000 L CNN F 2 "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical" H 8250 2200 50 0001 C CNN F 3 "~" H 8250 2200 50 0001 C CNN 1 8250 2200 1 0 0 -1 $EndComp $Comp L Device:LED D1 U 1 1 61405953 P 2550 2600 F 0 "D1" H 2543 2817 50 0000 C CNN F 1 "LED" H 2543 2726 50 0000 C CNN F 2 "LED_THT:LED_D1.8mm_W3.3mm_H2.4mm" H 2550 2600 50 0001 C CNN F 3 "~" H 2550 2600 50 0001 C CNN 1 2550 2600 1 0 0 -1 $EndComp $Comp L Device:R_Small_US R2 U 1 1 61406400 P 3150 2100 F 0 "R2" V 2945 2100 50 0000 C CNN F 1 "R_Small_US" V 3036 2100 50 0000 C CNN F 2 "Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Vertical" H 3150 2100 50 0001 C CNN F 3 "~" H 3150 2100 50 0001 C CNN 1 3150 2100 0 1 1 0 $EndComp $Comp L Device:R_Small_US R4 U 1 1 61406D49 P 4350 2950 F 0 "R4" V 4145 2950 50 0000 C CNN F 1 "R_Small_US" V 4236 2950 50 0000 C CNN F 2 "Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Vertical" H 4350 2950 50 0001 C CNN F 3 "~" H 4350 2950 50 0001 C CNN 1 4350 2950 0 1 1 0 $EndComp $Comp L Device:R_Small_US R1 U 1 1 6140734E P 3100 3250 F 0 "R1" V 2895 3250 50 0000 C CNN F 1 "R_Small_US" V 2986 3250 50 0000 C CNN F 2 "Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Vertical" H 3100 3250 50 0001 C CNN F 3 "~" H 3100 3250 50 0001 C CNN 1 3100 3250 0 1 1 0 $EndComp $Comp L Device:R_Small_US R3 U 1 1 61407F60 P 4250 2200 F 0 "R3" V 4045 2200 50 0000 C CNN F 1 "R_Small_US" V 4136 2200 50 0000 C CNN F 2 "Resistor_THT:R_Axial_DIN0204_L3.6mm_D1.6mm_P5.08mm_Vertical" H 4250 2200 50 0001 C CNN F 3 "~" H 4250 2200 50 0001 C CNN 1 4250 2200 0 1 1 0 $EndComp Text Label 5400 3400 2 50 ~ 0 +5V Text Label 5400 3300 2 50 ~ 0 GND Text Label 7000 2200 0 50 ~ 0 TX Text Label 7000 2700 0 50 ~ 0 RX Text Label 4050 2100 0 50 ~ 0 RX Text Label 4350 2200 0 50 ~ 0 GND Wire Wire Line 4050 2200 4150 2200 Text Label 4050 1800 0 50 ~ 0 +5V Text Label 3450 1900 2 50 ~ 0 +5V Wire Wire Line 3450 2100 3250 2100 Text Label 2400 2600 2 50 ~ 0 ONEWIRE Wire Wire Line 3050 2100 2700 2100 Wire Wire Line 2700 2100 2700 2600 Text Label 4050 3250 0 50 ~ 0 ONEWIRE Text Label 4050 3350 0 50 ~ 0 GND Text Label 4450 2950 0 50 ~ 0 +10V Wire Wire Line 4050 2950 4250 2950 Text Label 3450 3050 2 50 ~ 0 TX Wire Wire Line 3450 3250 3200 3250 Text Label 3000 3250 2 50 ~ 0 GND Text Label 8050 2400 2 50 ~ 0 +5V NoConn ~ 8050 2100 Text Label 8050 2200 2 50 ~ 0 +10V Text Label 8050 2300 2 50 ~ 0 GND $Comp L Connector:Conn_01x03_Male J1 U 1 1 61412821 P 8050 3300 F 0 "J1" H 8158 3581 50 0000 C CNN F 1 "Conn_01x03_Male" H 8158 3490 50 0000 C CNN F 2 "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical" H 8050 3300 50 0001 C CNN F 3 "~" H 8050 3300 50 0001 C CNN 1 8050 3300 1 0 0 -1 $EndComp Text Label 8250 3200 0 50 ~ 0 ONEWIRE Text Label 8250 3300 0 50 ~ 0 +10V Text Label 8250 3400 0 50 ~ 0 GND NoConn ~ 7000 2000 -NoConn ~ 7000 2100 NoConn ~ 7000 2300 NoConn ~ 7000 2400 NoConn ~ 7000 2500 -NoConn ~ 7000 2800 NoConn ~ 7000 3100 NoConn ~ 7000 3200 NoConn ~ 7000 3400 NoConn ~ 5400 3200 NoConn ~ 5400 3100 NoConn ~ 5400 2800 NoConn ~ 5400 2700 NoConn ~ 5400 2600 NoConn ~ 5400 2500 NoConn ~ 5400 2400 NoConn ~ 5400 2300 NoConn ~ 5400 2200 NoConn ~ 5400 2100 NoConn ~ 5400 2000 Text Label 7000 2600 0 50 ~ 0 GND Text Label 7000 3300 0 50 ~ 0 GND Text Label 5400 2900 2 50 ~ 0 GND NoConn ~ 4050 3050 NoConn ~ 4050 1900 NoConn ~ 8250 2600 $Comp L power:+5V #PWR0101 U 1 1 6141F44B P 4800 3900 F 0 "#PWR0101" H 4800 3750 50 0001 C CNN F 1 "+5V" H 4815 4073 50 0000 C CNN F 2 "" H 4800 3900 50 0001 C CNN F 3 "" H 4800 3900 50 0001 C CNN 1 4800 3900 1 0 0 -1 $EndComp $Comp L power:GND #PWR0102 U 1 1 6141F8CE P 5150 3900 F 0 "#PWR0102" H 5150 3650 50 0001 C CNN F 1 "GND" H 5155 3727 50 0000 C CNN F 2 "" H 5150 3900 50 0001 C CNN F 3 "" H 5150 3900 50 0001 C CNN 1 5150 3900 1 0 0 -1 $EndComp $Comp L power:+10V #PWR0103 U 1 1 61420082 P 5500 3850 F 0 "#PWR0103" H 5500 3700 50 0001 C CNN F 1 "+10V" H 5515 4023 50 0000 C CNN F 2 "" H 5500 3850 50 0001 C CNN F 3 "" H 5500 3850 50 0001 C CNN 1 5500 3850 1 0 0 -1 $EndComp Text Label 5150 3900 0 50 ~ 0 GND Text Label 5500 3850 0 50 ~ 0 +10V Text Label 4800 3900 0 50 ~ 0 +5V $Comp L Connector:Conn_01x04_Male J3 U 1 1 61414714 P 8100 4200 F 0 "J3" H 8208 4481 50 0000 C CNN F 1 "HTU21D_Breakout" H 8208 4390 50 0000 C CNN F 2 "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical" H 8100 4200 50 0001 C CNN F 3 "~" H 8100 4200 50 0001 C CNN 1 8100 4200 1 0 0 -1 $EndComp Text Label 8300 4200 0 50 ~ 0 GND Text Label 8300 4100 0 50 ~ 0 +3v3 Text Label 8300 4300 0 50 ~ 0 DA Text Label 8300 4400 0 50 ~ 0 CL -Text Label 7000 2900 0 50 ~ 0 -DA -Text Label 7000 3000 0 50 ~ 0 -CL $Comp L Connector:Conn_01x03_Male J4 U 1 1 61418482 P 8950 3300 F 0 "J4" H 9058 3581 50 0000 C CNN F 1 "Conn_01x03_Male" H 9058 3490 50 0000 C CNN F 2 "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical" H 8950 3300 50 0001 C CNN F 3 "~" H 8950 3300 50 0001 C CNN 1 8950 3300 1 0 0 -1 $EndComp Text Label 9150 3200 0 50 ~ 0 ONEWIRE Text Label 9150 3300 0 50 ~ 0 +10V Text Label 9150 3400 0 50 ~ 0 GND Text Label 3100 2200 0 50 ~ 0 1k Text Label 3050 3350 0 50 ~ 0 2k Text Label 4350 3050 0 50 ~ 0 10k Text Label 4200 2300 0 50 ~ 0 1.1-2k Text Label 5400 3000 2 50 ~ 0 +3v3 Text Label 7350 1950 0 50 ~ 0 D1-SCL,D6-SDA? +NoConn ~ 7000 2900 +NoConn ~ 7000 3000 +Text Label 7000 2100 0 50 ~ 0 +CL +Text Label 7000 2800 0 50 ~ 0 +DA $EndSCHEMATC diff --git a/src/main.cpp b/src/main.cpp --- a/src/main.cpp +++ b/src/main.cpp @@ -1,860 +1,923 @@ #include //this needs to be first, or it all crashes and burns... #include //this needs to be first, or it all crashes and burns... #include "config.h" #include //https://github.com/esp8266/Arduino #ifdef WANT_MDNS #include #endif /* WANT_MDNS */ #include #include //https://github.com/tzapu/WiFiManager #ifdef WANT_NTP #include #endif /* WANT_NTP */ #ifdef WANT_OTA #include #endif /* WANT_OTA */ #include #include #include -#include +//#include #include +#include #include #include #include #define DEBUG(X...) #define DEBUGCHAR(X...) //#define DEBUG(X...) do{if(Serial){Serial.end();Serial.swap();Serial.begin(15200);Serial.println(X);Serial.end();Serial.swap();Serial.begin(104);}}while(0) //#define DEBUGCHAR(X...) do{if(Serial){Serial.end();Serial.swap();Serial.begin(15200);Serial.print(X);Serial.end();Serial.swap();Serial.begin(104);}}while(0) #define EEPROM_BYTES_NEEDED 60 #define OTA_PASSWORD "0123" #define SLOW 250 #define MEDIUM 100 #define FAST 50 #define sleep(X) delay(X) #define ON 1 #define OFF 0 -#ifndef D5 -#if defined(ESP8266) -#define D5 (14) -#define D6 (12) -#define D7 (13) -#define D8 (15) -#define TX (1) -#elif defined(ESP32) -#define D5 (18) -#define D6 (19) -#define D7 (23) -#define D8 (5) -#define TX (1) -#endif -#endif +#define SENSOR_DA D6 +//#define SENSOR_DA D7 +#define SENSOR_CL D1 +//#define SENSOR_CL D8 + +// 'flash' button is pin 0 +#define BUTTON_PIN 0 + + +#define PREFIX "ha/hvac/" +#define PROJECTNAME "LGHP" + +//#ifndef D5 +//#if defined(ESP8266) +//#define D5 (14) +//#define D6 (12) +//#define D7 (13) +//#define D8 (15) +//#define TX (1) +//#elif defined(ESP32) +//#define D5 (18) +//#define D6 (19) +//#define D7 (23) +//#define D8 (5) +//#define TX (1) +//#endif +//#endif void publishTopicValue(char* strString, char* value); +void publishTopicValueRetain(char* strString, char* value, bool retain); void wifi_register_params(WiFiManager* wifiManager); SoftwareSerial swSer(D5,D3, 0); SoftwareSerial swSer1(D3,D2, 1); -#define PREFIX "ha/hvac/" -#define PROJECTNAME "lghp" IPAddress mqttAddress; WiFiClient wifiClient; String clientId; volatile long lastCharTime = 0; volatile long lastRx = 0; int charCount = 0; unsigned char charBuff[13]; unsigned char charBuffNew[13]; unsigned int checksum1 = 0; unsigned int checksum2 = 0; unsigned int lastChecksum = 0; boolean sensorPresent = true; byte powerByte = 0; byte fanByte = 0; byte modeByte = 0; byte plasmaByte = 0; byte tempByte = 0; byte zoneByte = 0; long previousMillis = 0; // will store last time loop ran long interval = 5000; // interval at which to limit loop int i; long previousMQTTCommand = 0; int waitForCommand = 1000; boolean changeWaiting = 0; boolean justChanged = 0; - +#define REPORT_INTERVAL 30 //******************************* // FUNCTIONS WiFiUDP ntpUdp; NTPClient timeClient(ntpUdp); //MQTT PubSubClient MQTTClient(wifiClient); // I2C pins for DHT sensor #define dataPin D6 #define clockPin D5 #define SMARTWEATHER_PORT 50222 // if 3.3v board is used IPAddress br_adr; WiFiUDP udp; -HTU2xD_SHT2x_SI70xx ht2x(HTU2xD_SENSOR, HUMD_12BIT_TEMP_14BIT); +HTU2xD_SHT2x_SI70xx ht2x(HTU2xD_SENSOR, HUMD_08BIT_TEMP_12BIT); String hubsn; String airsn; int reportfreq = 60; -// 'flash' button is pin 0 -#define BUTTON_PIN 0 + OneButton btn = OneButton( BUTTON_PIN, // Input pin for the button true, // Button is active LOW true // Enable internal pull-up resistor ); long ts; void publishTopicValue(char* strString, char* value) { DEBUGCHAR("S:"); DEBUGCHAR(strString); DEBUGCHAR("/"); DEBUG(value); MQTTClient.publish(strString, value); } +void publishTopicValueRetain(char* strString, const uint8_t* value, bool retain) { + DEBUGCHAR("S:"); + DEBUGCHAR(strString); + DEBUGCHAR("/"); + DEBUG(value); + MQTTClient.publish(strString, value, strlen((const char *)value), retain); +} + + void publishTopicValueLen(char* strString, char* value, int len) { DEBUGCHAR("S:"); DEBUGCHAR(strString); DEBUGCHAR("/"); DEBUG(value); MQTTClient.beginPublish(strString, len, 0); MQTTClient.write((byte *)value, len); MQTTClient.endPublish(); } char * make_topic(char * topic_type) { String path = PREFIX; path = path + clientId; path = path + "/"; path = path + topic_type; return strdup(path.c_str()); } void blink(int speed, int count) { pinMode(16, OUTPUT); for(; count > 0; count--) { digitalWrite(16, ON); sleep(speed); digitalWrite(16, OFF); sleep(speed); } digitalWrite(16, ON); } //! clear the wifi configuration and restart the device in AP mode. void resetEverything() { WiFi.enableSTA(true); WiFi.persistent(true); WiFi.disconnect(true); WiFi.persistent(false); delay(250); ESP.reset(); delay(5000); } /* the following definitions are used to indicate that values * should be saved to eprom or read from eeprom. */ bool shouldSaveConfig = false; bool enteredConfigMode = false; void configModeCallback (WiFiManager *myWiFiManager) { Serial.println("config mode"); enteredConfigMode = true; } void saveConfigCallback () { Serial.println("Should save config now"); if(enteredConfigMode) shouldSaveConfig = true; } void writeStringToEEPROM(int addrOffset, const String &strToWrite) { uint8_t len = strToWrite.length(); EEPROM.write(addrOffset, len); for (int i = 0; i < len; i++) { EEPROM.write(addrOffset + 1 + i, strToWrite[i]); } } String readStringFromEEPROM(int addrOffset) { uint8_t newStrLen; Serial.println("reading a string from eeprom"); EEPROM.get(addrOffset, newStrLen); char data[newStrLen + 1]; for (int i = 0; i < newStrLen; i++) { data[i] = EEPROM.read(addrOffset + 1 + i); } data[newStrLen] = '\0'; return String(data); } + +String wifi_get_mac_subset() { + uint8_t mac[6]; + char macStr[7] = { 0 }; + wifi_get_macaddr(STATION_IF, mac); + sprintf(macStr, "%02X%02X%02X", mac[3], mac[4], mac[5]); + return String(macStr); +} + //*********************************************** WiFiManagerParameter mqtt_ip ("mqtt_ip", "MQTT Server IP", "192.168.5.155", 15); WiFiManagerParameter client_id ("client_id", "MQTT Client ID", "Office", 15); WiFiManagerParameter hub_serial_number("hubsn", "HubSerialNumber", "10010", 7); WiFiManagerParameter air_serial_number("airsn", "AirSerialNumber", "10012", 7); WiFiManagerParameter report_frequency("reportfreq", "ReportFreq (seconds)", "60", 4); void wifi_register_params(WiFiManager* wifiManager) { wifiManager->addParameter(&mqtt_ip); wifiManager->addParameter(&client_id); wifiManager->addParameter(&hub_serial_number); wifiManager->addParameter(&air_serial_number); wifiManager->addParameter(&report_frequency); } void wifi_write_custom_params() { mqttAddress.fromString(mqtt_ip.getValue()); clientId = String(client_id.getValue()); writeStringToEEPROM(0, mqttAddress.toString()); // 7 bytes max writeStringToEEPROM(20, clientId); // 7 bytes max String hs ="HB-"; hs = hs + (hub_serial_number.getValue()); hubsn = hs; String as = "AR-"; as = as + (air_serial_number.getValue()); airsn = as; String frq = String(report_frequency.getValue()); reportfreq = (frq).toInt(); writeStringToEEPROM(30, hubsn); // 7 bytes max writeStringToEEPROM(40, airsn); // 7 bytes max writeStringToEEPROM(50, frq); // 4 bytes max DEBUG("Wrote mqtt settings to EEPROM"); if(!EEPROM.commit()) resetEverything(); delay(100); } void wifi_read_custom_params() { String mqtt_addr = readStringFromEEPROM(0); clientId = readStringFromEEPROM(20); hubsn = readStringFromEEPROM(30); airsn = readStringFromEEPROM(40); reportfreq = (readStringFromEEPROM(50)).toInt(); if(reportfreq < 30) reportfreq = 30; DEBUG("read mqtt settings from EEPROM"); DEBUG(mqtt_addr); DEBUG(clientId); DEBUG(hubsn); DEBUG(airsn); DEBUG(reportfreq); mqttAddress.fromString(mqtt_addr); } void callback(char* topic, uint8_t* payload,unsigned int length) { int topiclen = strlen(topic); DEBUGCHAR("Have message from topic "); DEBUG(topic); // If there has been no MQTT message received for a bit... if((millis() - previousMQTTCommand > waitForCommand) && (changeWaiting == 0)) { previousMQTTCommand = millis(); } if (topic[topiclen - 2] == '/'){ if (topic[topiclen - 1] == 'z'){ blink(FAST, 3); changeWaiting = 1; //DEBUG("Zones"); if (payload[3] == '1'){ bitWrite(charBuffNew[5],3, 1); }else{ bitWrite(charBuffNew[5],3, 0); } if (payload[2] == '1'){ bitWrite(charBuffNew[5],4, 1); }else{ bitWrite(charBuffNew[5],4, 0); } if (payload[1] == '1'){ bitWrite(charBuffNew[5],5, 1); }else{ bitWrite(charBuffNew[5],5, 0); } if (payload[0] == '1'){ bitWrite(charBuffNew[5],6, 1); }else{ bitWrite(charBuffNew[5],6, 0); } //DEBUG(charBuffNew[6],BIN); } else if (topic[topiclen - 1] == 'm'){ changeWaiting = 1; blink(FAST, 3); if (payload[0] == '0'){ //Cooling bitWrite(charBuffNew[1], 2, 0); bitWrite(charBuffNew[1], 3, 0); bitWrite(charBuffNew[1], 4, 0); } if (payload[0] == '1'){ //Dehumidify bitWrite(charBuffNew[1], 2, 1); bitWrite(charBuffNew[1], 3, 0); bitWrite(charBuffNew[1], 4, 0); } if (payload[0] == '2'){ //Fan only bitWrite(charBuffNew[1], 2, 0); bitWrite(charBuffNew[1], 3, 1); bitWrite(charBuffNew[1], 4, 0); } if (payload[0] == '3'){ //Auto bitWrite(charBuffNew[1], 2, 1); bitWrite(charBuffNew[1], 3, 1); bitWrite(charBuffNew[1], 4, 0); } if (payload[0] == '4'){ //Heating bitWrite(charBuffNew[1], 2, 0); bitWrite(charBuffNew[1], 3, 0); bitWrite(charBuffNew[1], 4, 1); } } else if (topic[topiclen - 1] == 't'){ changeWaiting = 1; blink(FAST, 3); char tmpChar[3] = {payload[0],payload[1], '\0'}; // Convert it to a null terminated string. unsigned int tempval = atoi(tmpChar)-15; // Take off the offset of 15 Degrees. bitWrite(charBuffNew[6], 0, bitRead(tempval, 0)); // Write the bits bitWrite(charBuffNew[6], 1, bitRead(tempval, 1)); bitWrite(charBuffNew[6], 2, bitRead(tempval, 2)); bitWrite(charBuffNew[6], 3, bitRead(tempval, 3)); } else if (topic[topiclen - 1] == 'f'){ changeWaiting = 1; blink(FAST, 3); if (payload[0] == '0'){ //Low bitWrite(charBuffNew[1],5,0); bitWrite(charBuffNew[1],6,0); } if (payload[0] == '1'){ //Med bitWrite(charBuffNew[1],5,1); bitWrite(charBuffNew[1],6,0); } if (payload[0] == '2'){ //High bitWrite(charBuffNew[1],5,0); bitWrite(charBuffNew[1],6,1); } } else if (topic[topiclen - 1] == 'p'){ changeWaiting = 1; blink(FAST, 3); //DEBUG("Power"); if (payload[0] == '1'){ charBuffNew[1] |= 0x02; }else{ charBuffNew[1] &= ~(0x02); } } else if (topic[topiclen - 1] == 'l'){ changeWaiting = 1; blink(FAST, 3); //DEBUG("Plasma"); if (payload[0] == '1'){ charBuffNew[2] |= 0x04; }else{ charBuffNew[2] ^= 0x04; } } } if (justChanged == 1 && changeWaiting == 1) changeWaiting = 0; } byte calcChecksum(){ unsigned int checksum; checksum2 = 0; for (int i = 0; i < 12; i++){ //DEBUGCHAR(charBuff[i]); //DEBUGCHAR("."); checksum2 = checksum2 + charBuffNew[i]; } checksum = checksum2 ^ 0x55; return checksum - 256; } uint8_t calcCRC() { unsigned int _txsum = 0; for (uint8_t i = 0; i < 12; i++) _txsum += charBuffNew[i]; return _txsum ^ 0x55 & 0xFF; } char * subPath; // = {'h', 'a', '/', 'm', 'o', 'd', '/', '5', '5', '5', '7', '/', '#','\0'}; byte topicNumber = 12; #define SLOW 250 #define MEDIUM 100 #define FAST 50 #define sleep(X) delay(X) #define ON 1 #define OFF 0 void mqttConnect() { blink(MEDIUM, 2); String path = String(PREFIX) + clientId + "/#"; - DEBUG("Connecting to broker"); + Serial.println("Connecting to broker"); while (!MQTTClient.connected()) { - if (MQTTClient.connect(clientId.c_str(), NULL, NULL, make_topic("status"), 0, false, "bye")){ - DEBUGCHAR("Subscribing to: "); - DEBUG(path.c_str()); + if (MQTTClient.connect(clientId.c_str(), NULL, NULL, make_topic("status"), 0, true, "bye\n")){ + Serial.println("Subscribing to: "); + Serial.println(path.c_str()); MQTTClient.subscribe(path.c_str()); - DEBUG("Subscribed!"); + Serial.println("Subscribed!"); blink(FAST, 2); } else { - DEBUG("Failed to connect!"); + Serial.println("Failed to connect!"); } } } void sendConfig(){ charBuffNew[0] = 0x48; // Slave charBuffNew[1] |= 0x01; // sending command // charBuffNew[2] = 0; //Clear out any other misc bits. // charBuffNew[3] = 0; //we dont need // charBuffNew[4] = 0; // charBuffNew[8] = 0; // charBuffNew[9] = 0; // charBuffNew[10] = 0; // charBuffNew[11] = 0; //Calculate the checksum for the data charBuffNew[12] = calcCRC(); //Send it of to the AC DEBUG("Sending to AC"); char * topic = make_topic("OUT"); publishTopicValueLen(topic, (char*)charBuffNew, 13); free(topic); blink(SLOW, 2); swSer1.write(charBuffNew,13); // Make sure we are not listening to the data we sent... //serialFlush(); } void publishSettings(){ char * topic = make_topic("RAW"); publishTopicValueLen(topic, (char*)charBuff, 13); free(topic); if(charBuff[0] != 168) return; if(!changeWaiting) { //Copy the existing bytes for (int i = 0; i < 13; i++) { charBuffNew[i] = charBuff[i]; } } //Power powerByte = bitRead(charBuff[1],1); // Fan speed 0-2 = Low, Med, High bitWrite(fanByte, 0, bitRead(charBuff[1],5)); bitWrite(fanByte, 1, bitRead(charBuff[1],6)); //Mode 0 = Cool, 1 = Dehumidify, 2 = Fan only, 3 = Auto, 4 = Heat bitWrite(modeByte,0, bitRead(charBuff[1],2)); bitWrite(modeByte,1, bitRead(charBuff[1],3)); bitWrite(modeByte,2, bitRead(charBuff[1],4)); //Mode 0 = Off, 1 = On plasmaByte = (charBuff[2] & 0x04)? 1:0; //Set Temp - Binary 0011 -> 1111 = 18 - 30 Deg (decimal 3 offset in value, starts at 18, possibly cool can be set at 15?) bitWrite(tempByte,0, bitRead(charBuff[6],0)); bitWrite(tempByte,1, bitRead(charBuff[6],1)); bitWrite(tempByte,2, bitRead(charBuff[6],2)); bitWrite(tempByte,3, bitRead(charBuff[6],3)); //Zone control - Single bits for each zone bitWrite(zoneByte,0, bitRead(charBuff[5],3)); //Zone 4 bitWrite(zoneByte,1, bitRead(charBuff[5],4)); //Zone 3 bitWrite(zoneByte,2, bitRead(charBuff[5],5)); //Zone 2 bitWrite(zoneByte,3, bitRead(charBuff[5],6)); //Zone 1 // char strPath1[] = {'h', 'a', '/', 'm', 'o', 'd', '/', id[0], id[1], id[2], id[3], '/', 'P','\0'}; // Power State // char strPath2[] = {'h', 'a', '/', 'm', 'o', 'd', '/', id[0], id[1], id[2], id[3], '/', 'T','\0'}; //Set Temp // char strPath3[] = {'h', 'a', '/', 'm', 'o', 'd', '/', id[0], id[1], id[2], id[3], '/', 'M','\0'}; //Mode // char strPath4[] = {'h', 'a', '/', 'm', 'o', 'd', '/', id[0], id[1], id[2], id[3], '/', 'Z','\0'}; //Zones // char strPath5[] = {'h', 'a', '/', 'm', 'o', 'd', '/', id[0], id[1], id[2], id[3], '/', 'F','\0'}; //Fan char tempChar[2] = {powerByte + 48, '\0'}; topic = make_topic("P"); publishTopicValueLen(topic, tempChar, 1); free(topic); tempChar[0] = plasmaByte + 48; topic = make_topic("L"); publishTopicValueLen(topic, tempChar, 1); free(topic); tempChar[0] = modeByte + 48; topic = make_topic("M"); publishTopicValueLen(topic, tempChar, 1); free(topic); tempChar[0] = fanByte + 48; topic = make_topic("F"); publishTopicValueLen(topic, tempChar, 1); free(topic); char charStr[5] = {bitRead(zoneByte,3)+48, bitRead(zoneByte,2)+48, bitRead(zoneByte,1)+48, bitRead(zoneByte,0)+48, '\0'}; topic = make_topic("Z"); publishTopicValueLen(topic, charStr, 4); free(topic); char tmpChar[3]; char* myPtr = &tmpChar[0]; snprintf(myPtr, 3, "%02u", tempByte+15); topic = make_topic("T"); publishTopicValueLen(topic, tmpChar, 2); free(topic); lastChecksum = charBuff[12]; } //*********************************************** void setup() { char _hostname[20]; uint8_t mac[6]; // put your setup code here, to run once: Serial.begin(115200); - DEBUG("Startup"); + // EEPROM.begin(512); +// // write a 0 to all 512 bytes of the EEPROM +// for (int i = 0; i < 512; i++) { EEPROM.write(i, 0); } +// +// // turn the LED on when we're done +// pinMode(13, OUTPUT); +// digitalWrite(13, HIGH); +// EEPROM.end(); +// + DEBUG("Startup"); //Set up software serial at 104 baud to read from AC pinMode(D2, OUTPUT); // digitalWrite(D2, 0); // delay(300); // digitalWrite(D2, 1); // delay(300); // digitalWrite(D2, 0); // delay(300); // digitalWrite(D2, 1); // delay(300); // digitalWrite(D2, 0); swSer.begin(104); swSer1.begin(104); //Set up hardware serial 1 at 104 baud to write AC (the read pin for this port is unavailable) // Serial1.begin(104); //WiFiManager //Local intialization. Once its business is done, there is no need to keep it around WiFiManager wifiManager; + String ssid = PROJECTNAME + String("-"); + ssid += wifi_get_mac_subset(); + wifi_register_params(&wifiManager); + wifiManager.setHostname(ssid.c_str()); + //WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); //WiFi.macAddress(mac); //sprintf(_hostname, PROJECTNAME "-%02x%02x%02x%02x%02x%02x", // mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); //WiFi.hostname(_hostname); //exit after config instead of connecting wifiManager.setBreakAfterConfig(true); wifiManager.setAPCallback(configModeCallback); wifiManager.setSaveConfigCallback(saveConfigCallback); //reset settings - for testing - //wifiManager.resetSettings(); + wifiManager.resetSettings(); //tries to connect to last known settings //if it does not connect it starts an access point with the specified name //here "AutoConnectAP" with password "password" //and goes into a blocking loop awaiting configuration if (!wifiManager.autoConnect()) { DEBUG("WifiManager: failed to connect, we should reset as see if it connects"); delay(3000); ESP.reset(); delay(5000); } EEPROM.begin(EEPROM_BYTES_NEEDED); if (shouldSaveConfig) { wifi_write_custom_params(); } else if(1){ wifi_read_custom_params(); } ArduinoOTA.onStart([]() { DEBUG("OTA Start"); }); ArduinoOTA.onEnd([]() { DEBUG("\nOTA End"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("OTA: Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("OTA Error[%u]: ", error); if (error == OTA_AUTH_ERROR) DEBUG("OTA: Auth Failed"); else if (error == OTA_BEGIN_ERROR) DEBUG("OTA: Begin Failed"); else if (error == OTA_CONNECT_ERROR) DEBUG("OTA: Connect Failed"); else if (error == OTA_RECEIVE_ERROR) DEBUG("OTA: Receive Failed"); else if (error == OTA_END_ERROR) DEBUG("OTA: End Failed"); }); ArduinoOTA.setPassword((const char *)OTA_PASSWORD); //if you get here you have connected to the WiFi DEBUG("connected...yay :)"); ArduinoOTA.begin(); DEBUG("local ip"); DEBUG(WiFi.localIP()); DEBUG("mqtt ip"); DEBUG(mqttAddress); DEBUG("client id"); DEBUG(clientId); + br_adr = WiFi.localIP(); + br_adr[3] = 255; + MQTTClient.setServer(mqttAddress, 1883); MQTTClient.setCallback(callback); timeClient.begin(); udp.begin(SMARTWEATHER_PORT); -// while (ht2x.begin() != true) //reset sensor, set heater off, set resolution, check power (sensor doesn't operate correctly if VDD < +2.25v) -// { -// sensorPresent = false; -// Serial.println(F("HTU2xD/SHT2x not connected, fail or VDD < +2.25v")); //(F()) save string to flash & keeps dynamic memory free -// } + while (ht2x.begin(SENSOR_DA, SENSOR_CL) != true) //reset sensor, set heater off, set resolution, check power (sensor doesn't operate correctly if VDD < +2.25v) + { + sensorPresent = false; + Serial.println(F("HTU2xD/SHT2x not connected, fail or VDD < +2.25v")); //(F()) save string to flash & keeps dynamic memory free + } Serial.println(F("HTU2xD/SHT2x OK")); delay(1000); Serial.println("ready to read"); btn.attachLongPressStart(resetEverything); } unsigned long lastPublish = 0; unsigned long lastReport = 0; unsigned long lastObservation = 0; unsigned long tsm = 0; unsigned int reportcnt = 0; void thSensorLoop() { - if ((tsm / 1000) > (lastReport + 30)) { - lastReport = millis() / 1000; + if ((tsm) > (lastReport + (REPORT_INTERVAL*1000))) { + sleep(50); + lastReport = tsm; #ifdef WANT_NTP ts = timeClient.getEpochTime(); #endif /* WANT_NTP */ - if (sensorPresent) { - StaticJsonDocument<200> doc; + // always send the hub message + + StaticJsonDocument<220> doc; + WriteBufferingStream bufferedFile{udp, 64}; doc["serial_number"] = hubsn; doc["type"] = "hub_status"; doc["firmware_revision"] = FIRMWARE_REVISION; - doc["uptime"] = millis() / 1000; + doc["uptime"] = tsm / 1000; doc["rssi"] = WiFi.RSSI(); doc["timestamp"] = ts; udp.beginPacket(br_adr, SMARTWEATHER_PORT); - serializeJson(doc, udp); - udp.println(); + serializeJson(doc, bufferedFile); + bufferedFile.flush(); udp.endPacket(); reportcnt++; - } - if (1) { - StaticJsonDocument<200> doc; + if (sensorPresent) { + StaticJsonDocument<220> doc; + WriteBufferingStream bufferedFile{udp, 64}; doc["serial_number"] = airsn; doc["hub_sn"] = hubsn; doc["type"] = "device_status"; doc["firmware_revision"] = FIRMWARE_REVISION; - doc["uptime"] = millis() / 1000; + doc["uptime"] = tsm / 1000; doc["rssi"] = WiFi.RSSI(); doc["hub_rssi"] = WiFi.RSSI(); doc["voltage"] = 0.0; doc["timestamp"] = ts; udp.beginPacket(br_adr, SMARTWEATHER_PORT); - serializeJson(doc, udp); - udp.println(); + serializeJson(doc, bufferedFile); + bufferedFile.flush(); udp.endPacket(); } } - if ((tsm / 1000) > (lastObservation + reportfreq)) { - StaticJsonDocument<250> doc; + + if (((tsm) > (lastObservation + (reportfreq * 1000)))) { + StaticJsonDocument<375> doc; + float t = 0.0, h = 0.0; + lastObservation = tsm; blink(FAST, 2); -#ifdef WANT_NTP - ts = timeClient.getEpochTime(); -#endif /* WANT_NTP */ + Serial.println("Sending weather report"); + + t = ht2x.readTemperature(); + h = ht2x.readHumidity(); - lastObservation = (tsm / 1000); + Serial.print("T "); + Serial.println(t); + + Serial.print("H "); + Serial.println(h); + doc["serial_number"] = airsn; doc["hub_sn"] = hubsn; doc["type"] = "obs_air"; doc["firmware_revision"] = FIRMWARE_REVISION; JsonArray obs = doc.createNestedArray("obs"); JsonArray obsValues = obs.createNestedArray(); obsValues.add(ts); obsValues.add(0.0); + + obsValues.add(t); + obsValues.add(h); - obsValues.add(0.0); - obsValues.add(0.0); - -// obsValues.add(ht2x.readTemperature()); -// obsValues.add(ht2x.readHumidity()); obsValues.add(0); obsValues.add(0); obsValues.add(0.0); obsValues.add((reportfreq / 60)); + Serial.println("built report"); + sleep(50); + udp.beginPacket(br_adr, SMARTWEATHER_PORT); serializeJson(doc, udp); - udp.println(); udp.endPacket(); + Serial.println("sent report"); } delay(100); } void loop() { #ifdef WANT_NTP timeClient.update(); #endif /* WANT_NTP */ #ifdef WANT_OTA ArduinoOTA.handle(); #endif /* WANT_OTA */ // Reset every RESET_INTERVAL tsm = millis(); if(tsm > RESET_INTERVAL) { + Serial.println("Periodic reset"); + ESP.restart(); delay(1000); } btn.tick(); MQTTClient.loop(); + thSensorLoop(); + // swSer.write("A"); // swSer.write("B"); // swSer.write("A"); // swSer.write("B"); - if(tsm - previousMillis > interval) { + if((tsm - previousMillis) > interval) { previousMillis = tsm; if(!MQTTClient.connected()) mqttConnect(); else { char * topic = make_topic("status"); - String m = "hello "; - m = m + millis(); - publishTopicValue(topic, (char *)m.c_str()); + String m = "hello"; +// m = m + millis(); + publishTopicValueRetain(topic, (const uint8_t*)(m.c_str()), true); free(topic); } if (justChanged == 1){ justChanged = 0; //serialFlush(); //Get rid of any data we received in the mean time. } } if((millis() - previousMQTTCommand > waitForCommand) && (changeWaiting == 1)) { //More than 1 second and we have received an update via MQTT //We have received some updates and we need to send them off via serial. while (millis() - lastRx < 2000) { //Make sure we are not stomping on someone else sending delay(100); //Main unit sends every 60 seconds, Master every 20 } sendConfig(); delay(200); sendConfig(); //Twice, just to be sure (This is how the factory unit operates...) changeWaiting = 0; } if (swSer.available()) { lastCharTime=millis(); charBuff[charCount] = swSer.read(); charCount++; // publishTopicValueLen("ha/hvac/Office/bytes", (char *)charBuff, 1); // DEBUGCHAR("Have bytes. "); // DEBUG(charCount); if (charCount == 13){ // publishTopicValueLen("ha/hvac/Office/bytes", (char *)charBuff, charCount); DEBUGCHAR("R: "); for (int i=0; i < 12; i++){ DEBUGCHAR(charBuff[i],DEC); DEBUGCHAR(","); } DEBUG(charBuff[12],DEC); charCount = 0; //if (charBuff[0] == 168){ // && charBuff[12] != lastChecksum){ //Only publish data back to MQTT from the Master controller. lastRx = millis(); //Track when we received the last 168 (master) packet // TODO need to verify checksum and reset framing if necessary. if (changeWaiting == 0) publishSettings(); // If there is nothing pending FROM MQTT, Send the data off to MQTT // } } } if (charCount > 0 && millis() - lastCharTime > 200){ charCount = 0; //Expired or we got half a packet. Ignore DEBUG("RESET charcount"); } }