diff --git a/include/hasp_conf.h b/include/hasp_conf.h index a14b936f..96b88a60 100644 --- a/include/hasp_conf.h +++ b/include/hasp_conf.h @@ -85,6 +85,10 @@ #include "hasp_ota.h" #endif +#if HASP_USE_TASMOTA_SLAVE>0 +#include "hasp_slave.h" +#endif + #endif #ifndef FPSTR diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 854b9db4..2dae3a19 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -331,8 +331,10 @@ void debugPreSetup(JsonObject settings) if(baudrate >= 9600u) { /* the baudrates are stored divided by 10 */ #ifdef STM32_CORE_VERSION_MAJOR - Serial.setRx(PA3); // User Serial2 - Serial.setTx(PA2); + #ifndef STM32_SERIAL1 // Define what Serial port to use for log output + Serial.setRx(PA3); // User Serial2 + Serial.setTx(PA2); + #endif #endif Serial.begin(baudrate); /* prepare for possible serial debug */ delay(10); diff --git a/src/hasp_dispatch.cpp b/src/hasp_dispatch.cpp index bed14991..b605825e 100644 --- a/src/hasp_dispatch.cpp +++ b/src/hasp_dispatch.cpp @@ -51,6 +51,8 @@ void dispatchOutput(int output, bool state) #if defined(ARDUINO_ARCH_ESP32) ledcWrite(99, state ? 1023 : 0); // ledChannel and value +#elif defined(STM32_CORE_VERSION) + digitalWrite(HASP_OUTPUT_PIN, state); #else analogWrite(pin, state ? 1023 : 0); #endif @@ -95,12 +97,6 @@ void dispatchAttribute(String strTopic, const char * payload) { if(strTopic.startsWith("p[")) { dispatchButtonAttribute(strTopic, payload); - } else if(strTopic.startsWith(F("output"))) { -#if defined(ARDUINO_ARCH_ESP8266) - uint8_t state = isON(payload) ? HIGH : LOW; - digitalWrite(D1, state); -#endif - } else if(strTopic == F("page")) { dispatchPage(payload); @@ -138,9 +134,12 @@ void dispatchPage(String strPageid) String strPage((char *)0); strPage.reserve(128); strPage = haspGetPage(); -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 mqtt_send_state(F("page"), strPage.c_str()); #endif +#if HASP_USE_TASMOTA_SLAVE > 0 + slave_send_state(F("page"), strPage.c_str()); +#endif } void dispatchClearPage(String strPageid) @@ -160,11 +159,16 @@ void dispatchDim(String strDimLevel) if(strDimLevel.length() != 0) guiSetDim(strDimLevel.toInt()); dispatchPrintln(F("DIM"), strDimLevel); -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 char buffer[8]; itoa(guiGetDim(), buffer, DEC); mqtt_send_state(F("dim"), buffer); #endif +#if HASP_USE_TASMOTA_SLAVE > 0 + char buffer[8]; + itoa(guiGetDim(), buffer, DEC); + slave_send_state(F("dim"), buffer); +#endif } void dispatchBacklight(String strPayload) @@ -177,9 +181,13 @@ void dispatchBacklight(String strPayload) // Return the current state strPayload = getOnOff(guiGetBacklight()); -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 mqtt_send_state(F("light"), strPayload.c_str()); #endif +#if HASP_USE_TASMOTA_SLAVE > 0 + slave_send_state(F("light"), strPayload.c_str()); +#endif + } void dispatchCommand(String cmnd) @@ -266,8 +274,10 @@ void dispatchJsonl(char * payload) void dispatchIdle(const char * state) { -#if HASP_USE_MQTT>0 +#if HASP_USE_MQTT > 0 mqtt_send_state(F("idle"), state); +#elif HASP_USE_TASMOTA_SLAVE > 0 + slave_send_state(F("idle"), state); #else Log.notice(F("OUT: idle = %s"), state); #endif @@ -276,11 +286,11 @@ void dispatchIdle(const char * state) void dispatchReboot(bool saveConfig) { if(saveConfig) configWriteConfig(); -#if HASP_USE_MQTT>0 +#if HASP_USE_MQTT > 0 mqttStop(); // Stop the MQTT Client first #endif debugStop(); -#if HASP_USE_WIFI>0 +#if HASP_USE_WIFI > 0 wifiStop(); #endif Log.verbose(F("-------------------------------------")); @@ -294,6 +304,9 @@ void dispatch_button(uint8_t id, const char * event) #if HASP_USE_MQTT > 0 mqtt_send_input(id, event); #endif +#if HASP_USE_TASMOTA_SLAVE + slave_send_input(id, event); +#endif } void dispatchWebUpdate(const char * espOtaUrl) @@ -308,6 +321,8 @@ void IRAM_ATTR dispatch_obj_attribute_str(uint8_t pageid, uint8_t btnid, const c { #if HASP_USE_MQTT > 0 mqtt_send_obj_attribute_str(pageid, btnid, attribute, data); +#elif HASP_USE_TASMOTA_SLAVE > 0 + slave_send_obj_attribute_str(pageid, btnid, attribute, data); #else Log.notice(F("OUT: json = {\"p[%u].b[%u].%s\":\"%s\"}"), pageid, btnid, attribute, data); #endif @@ -356,14 +371,14 @@ void dispatchConfig(const char * topic, const char * payload) haspGetConfig(settings); } -#if HASP_USE_WIFI +#if HASP_USE_WIFI > 0 else if(strcmp_P(topic, PSTR("wifi")) == 0) { if(update) wifiSetConfig(settings); else wifiGetConfig(settings); } -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 else if(strcmp_P(topic, PSTR("mqtt")) == 0) { if(update) mqttSetConfig(settings); @@ -371,11 +386,11 @@ void dispatchConfig(const char * topic, const char * payload) mqttGetConfig(settings); } #endif -#if HASP_USE_TELNET +#if HASP_USE_TELNET > 0 // else if(strcmp_P(topic, PSTR("telnet")) == 0) // telnetGetConfig(settings[F("telnet")]); #endif -#if HASP_USE_MDNS +#if HASP_USE_MDNS > 0 else if(strcmp_P(topic, PSTR("mdns")) == 0) { if(update) mdnsSetConfig(settings); @@ -383,7 +398,7 @@ void dispatchConfig(const char * topic, const char * payload) mdnsGetConfig(settings); } #endif -#if HASP_USE_HTTP +#if HASP_USE_HTTP > 0 else if(strcmp_P(topic, PSTR("http")) == 0) { if(update) httpSetConfig(settings); @@ -397,8 +412,10 @@ void dispatchConfig(const char * topic, const char * payload) if(!update) { settings.remove(F("pass")); // hide password in output size_t size = serializeJson(doc, buffer, sizeof(buffer)); -#if HASP_USE_MQTT +#if HASP_USE_MQTT > 0 mqtt_send_state(F("config"), buffer); +#elif HASP_USE_TASMOTA > 0 + slave_send_state(F("config"), buffer); #else Log.notice(F("OUT: config %s = %s"),topic,buffer); #endif diff --git a/src/hasp_gpio.cpp b/src/hasp_gpio.cpp index 1ab5cefb..4094d7e6 100644 --- a/src/hasp_gpio.cpp +++ b/src/hasp_gpio.cpp @@ -7,4 +7,8 @@ void gpioSetup() pinMode(D1, OUTPUT); pinMode(D2, INPUT_PULLUP); #endif +#if defined(STM32_CORE_VERSION) + pinMode(HASP_OUTPUT_PIN, OUTPUT); + pinMode(HASP_INPUT_PIN, INPUT_PULLUP); +#endif } \ No newline at end of file diff --git a/src/hasp_gui.cpp b/src/hasp_gui.cpp index 021b890a..3232e7c3 100644 --- a/src/hasp_gui.cpp +++ b/src/hasp_gui.cpp @@ -925,6 +925,7 @@ bool guiGetConfig(const JsonObject & settings) v.set(calData[i]); } else { changed = true; + tft.setTouch(calData); } i++; } @@ -935,6 +936,8 @@ bool guiGetConfig(const JsonObject & settings) for(uint8_t i = 0; i < 5; i++) { array.add(calData[i]); } + changed = true; + tft.setTouch(calData); } if(changed) configOutput(settings); @@ -983,14 +986,13 @@ bool guiSetConfig(const JsonObject & settings) } if(calData[0] != 0 || calData[1] != 65535 || calData[2] != 0 || calData[3] != 65535) { - Log.trace(F("calData set [%u, %u, %u, %u, %u]"), calData[0], calData[1], calData[2], calData[3], - calData[4]); + Log.trace(F("calData set [%u, %u, %u, %u, %u]"), calData[0], calData[1], calData[2], calData[3],calData[4]); oobeSetAutoCalibrate(false); } else { Log.notice(F("First Touch Calibration enabled")); oobeSetAutoCalibrate(true); } - + if (status) tft.setTouch(calData); changed |= status; } diff --git a/src/hasp_slave.cpp b/src/hasp_slave.cpp new file mode 100644 index 00000000..0fc479ef --- /dev/null +++ b/src/hasp_slave.cpp @@ -0,0 +1,147 @@ +/********************* + * INCLUDES + *********************/ +#include "hasp_slave.h" +#include +#include "ArduinoJson.h" +#include "ArduinoLog.h" +#include "hasp_dispatch.h" +#include "hasp_gui.h" +#include "tasmotaSlave.h" + +// set RX and TX pins +HardwareSerial Serial2(PD6, PD5); +TasmotaSlave slave(&Serial2); + +#define slaveNodeTopic "hasp/" + +unsigned long updateLedTimer = 0; // timer in msec for tele mqtt send +unsigned long updatLedPeriod = 1000; // timer in msec for tele mqtt send + +bool ledstate = false; + + +void IRAM_ATTR slave_send_state(const __FlashStringHelper * subtopic, const char * payload) +{ + // page = 0 + // p[0].b[0].attr = abc + // dim = 100 + // idle = 0/1 + // light = 0/1 + // brightness = 100 + + char cBuffer[strlen(payload) + 64]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/%s %s"), slaveNodeTopic ,subtopic, payload); + slave.ExecuteCommand((char*)cBuffer); + + // Log after char buffers are cleared + Log.notice(F("TAS PUB: %sstate/%S = %s"), slaveNodeTopic, subtopic, payload); +} + +void IRAM_ATTR slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data) +{ + char cBuffer[192]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf_P(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/json {\"p[%u].b[%u].%s\":\"%s\"}"), slaveNodeTopic, pageid, btnid, attribute, data); + slave.ExecuteCommand((char*)cBuffer); + // Log after char buffers are cleared + Log.notice(F("TAS PUB: %sstate/json = {\"p[%u].b[%u].%s\":\"%s\"}"), slaveNodeTopic, pageid, btnid, attribute, data); +} + +void slave_send_input(uint8_t id, const char * payload) +{ + // Log.trace(F("MQTT TST: %sstate/input%u = %s"), mqttNodeTopic, id, payload); // to be removed + + char cBuffer[strlen(payload) + 64]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf_P(cBuffer, sizeof(cBuffer), PSTR("publish %sstate/input%u %s"), slaveNodeTopic, id, payload); + slave.ExecuteCommand((char*)cBuffer); + + // Log after char buffers are cleared + Log.notice(F("TAS PUB: %sstate/input%u = %s"), slaveNodeTopic, id, payload); +} + +// void slave_send_statusupdate() +// { // Periodically publish a JSON string indicating system status +// char data[3 * 128]; +// { +// char buffer[128]; +// snprintf_P(data, sizeof(data), PSTR("{\"status\":\"available\",\"version\":\"%s\",\"uptime\":%lu,"), +// haspGetVersion().c_str(), long(millis() / 1000)); +// strcat(buffer, data); +// snprintf_P(buffer, sizeof(buffer), PSTR("\"heapFree\":%u,\"heapFrag\":%u,\"espCore\":\"%s\","), +// ESP.getFreeHeap(), halGetHeapFragmentation(), halGetCoreVersion().c_str()); +// strcat(data, buffer); +// snprintf_P(buffer, sizeof(buffer), PSTR("\"espCanUpdate\":\"false\",\"page\":%u,\"numPages\":%u}"), +// haspGetPage(), (HASP_NUM_PAGES)); +// strcat(data, buffer); +// snprintf_P(buffer, sizeof(buffer), PSTR("\"tftDriver\":\"%s\",\"tftWidth\":%u,\"tftHeight\":%u}"), +// tftDriverName().c_str(), (TFT_WIDTH), (TFT_HEIGHT)); +// strcat(data, buffer); +// } +// slave_send_state(F("statusupdate"), data); +// debugLastMillis = millis(); +// } + +void TASMO_DATA_RECEIVE(char *data) +{ + Log.verbose(F("TAS: Slave IN [%s]"), data); + + char slvCmd[20],slvVal[60]; + memset(slvCmd, 0 ,sizeof(slvCmd)); + memset(slvVal, 0 ,sizeof(slvVal)); + sscanf(data,"%s %s", slvCmd, slvVal); + + Log.verbose(F("TAS: Cmd[%s] Val[%s]"), slvCmd, slvVal); + + if (!strcmp(slvCmd, "calData")){ + if (strlen(slvVal) != 0) { + char cBuffer[strlen(slvVal) + 24]; + memset(cBuffer, 0 ,sizeof(cBuffer)); + snprintf_P(cBuffer, sizeof(cBuffer), PSTR("{'calibration':[%s]}"), slvVal); + dispatchConfig("gui",cBuffer); + } else { + dispatchConfig("gui",""); + } + } else if (!strcmp(slvCmd, "jsonl")) { + dispatchJsonl(slvVal); + } else { + char cBuffer[strlen(data)+1]; + snprintf_P(cBuffer, sizeof(cBuffer), PSTR("%s=%s"), slvCmd, slvVal); + dispatchCommand(cBuffer); + } +} + +void TASMO_EVERY_SECOND(void) +{ + if (ledstate) { + ledstate = false; + digitalWrite(HASP_OUTPUT_PIN, 1); + // Log.verbose(F("LED OFF")); + } else { + ledstate = true; + digitalWrite(HASP_OUTPUT_PIN, 0); + // Log.verbose(F("LED ON")); + } +} + +void slaveSetup() +{ + Serial2.begin(HASP_SLAVE_SPEED); + // slave.attach_FUNC_EVERY_SECOND(TASMO_EVERY_SECOND); + slave.attach_FUNC_COMMAND_SEND(TASMO_DATA_RECEIVE); + + Log.notice(F("TAS: HASP SLAVE LOADED")); +} + +void slaveLoop(void) +{ + slave.loop(); + // demo code to run the led without tasmota + // if ((millis() - updateLedTimer) >= updatLedPeriod) { + // updateLedTimer = millis(); + // TASMO_EVERY_SECOND(); + // } + +} \ No newline at end of file diff --git a/src/hasp_slave.h b/src/hasp_slave.h new file mode 100644 index 00000000..89db9964 --- /dev/null +++ b/src/hasp_slave.h @@ -0,0 +1,20 @@ +#ifndef HASP_SLAVE_H +#define HASP_SLAVE_H + +#include "ArduinoJson.h" + +#define HASP_SLAVE_SPEED 38400 + +void TASMO_EVERY_SECOND(void); +void TASMO_DATA_RECEIVE(char *data); +void IRAM_ATTR slave_send_state(const __FlashStringHelper * subtopic, const char * payload); +void IRAM_ATTR slave_send_obj_attribute_str(uint8_t pageid, uint8_t btnid, const char * attribute, const char * data); +void slave_send_input(uint8_t id, const char * payload); +void slave_send_statusupdate(); + + +void slaveSetup(); +void slaveLoop(void); + + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 5bb44c72..020416c5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -80,6 +80,10 @@ void setup() buttonSetup(); #endif +#if HASP_USE_TASMOTA_SLAVE + slaveSetup(); +#endif + mainLastLoopTime = millis() - 1000; // reset loop counter } @@ -132,6 +136,10 @@ void loop() #endif // WIFI +#if HASP_USE_TASMOTA_SLAVE + slaveLoop(); +#endif // TASMOTASLAVE + // Every Second Loop if(millis() - mainLastLoopTime >= 1000) { /* Run Every Second */