diff --git a/src/cmnds/cmd_channels.c b/src/cmnds/cmd_channels.c index 45c0b160f..66976a785 100644 --- a/src/cmnds/cmd_channels.c +++ b/src/cmnds/cmd_channels.c @@ -148,14 +148,17 @@ static int CMD_GetChannel(const void *context, const char *cmd, const char *args } static int CMD_GetReadings(const void *context, const char *cmd, const char *args, int cmdFlags){ #ifndef OBK_DISABLE_ALL_DRIVERS - char tmp[64]; + char tmp[96]; float v, c, p; + float e, elh; v = DRV_GetReading(OBK_VOLTAGE); c = DRV_GetReading(OBK_CURRENT); p = DRV_GetReading(OBK_POWER); + e = DRV_GetReading(OBK_CONSUMPTION_TOTAL); + elh = DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR); - sprintf(tmp, "%f %f %f",v,c,p); + sprintf(tmp, "%f %f %f %f %f",v,c,p,e,elh); if(cmdFlags & COMMAND_FLAG_SOURCE_TCP) { ADDLOG_INFO(LOG_FEATURE_RAW, tmp); diff --git a/src/cmnds/cmd_eventHandlers.c b/src/cmnds/cmd_eventHandlers.c index ff68e1b2e..a17afd09d 100644 --- a/src/cmnds/cmd_eventHandlers.c +++ b/src/cmnds/cmd_eventHandlers.c @@ -122,6 +122,10 @@ static int EVENT_ParseEventName(const char *s) { return CMD_EVENT_PIN_ONDBLCLICK; if(!stricmp(s,"OnChannelChange")) return CMD_EVENT_CHANNEL_ONCHANGE; + if(!stricmp(s,"energycounter")) + return CMD_EVENT_CHANGE_CONSUMPTION_TOTAL; + if(!stricmp(s,"energycounter_last_hour")) + return CMD_EVENT_CHANGE_CONSUMPTION_LAST_HOUR; return CMD_EVENT_NONE; } static bool EVENT_EvaluateCondition(int code, int argument, int next) { diff --git a/src/cmnds/cmd_public.h b/src/cmnds/cmd_public.h index e34429975..e14c8abf1 100644 --- a/src/cmnds/cmd_public.h +++ b/src/cmnds/cmd_public.h @@ -42,6 +42,8 @@ enum EventCode { CMD_EVENT_CHANGE_VOLTAGE, // must match order in drv_bl0942.c CMD_EVENT_CHANGE_CURRENT, CMD_EVENT_CHANGE_POWER, + CMD_EVENT_CHANGE_CONSUMPTION_TOTAL, + CMD_EVENT_CHANGE_CONSUMPTION_LAST_HOUR, // this is for ToggleChannelOnToggle CMD_EVENT_PIN_ONTOGGLE, diff --git a/src/driver/drv_bl_shared.c b/src/driver/drv_bl_shared.c index 6b2e871d3..b88e3f11b 100644 --- a/src/driver/drv_bl_shared.c +++ b/src/driver/drv_bl_shared.c @@ -9,6 +9,7 @@ #include "drv_local.h" #include "drv_uart.h" #include "../httpserver/new_http.h" +#include "../cJSON/cJSON.h" int stat_updatesSkipped = 0; int stat_updatesSent = 0; @@ -28,49 +29,88 @@ float lastSentValues[OBK_NUM_MEASUREMENTS]; float energyCounter = 0.0f; portTickType energyCounterStamp; +float energyCounterMinutes[60]; +portTickType energyCounterMinutesStamp; +long energyCounterMinutesIndex; + // how much update frames has passed without sending MQTT update of read values? int noChangeFrames[OBK_NUM_MEASUREMENTS]; int noChangeFrameEnergyCounter; float lastSentEnergyCounterValue = 0.0f; float changeSendThresholdEnergy = 0.1f; +float lastSentEnergyCounterLastHour = 0.0f; // how much of value have to change in order to be send over MQTT again? int changeSendThresholds[OBK_NUM_MEASUREMENTS] = { - 0.25f, // voltage - OBK_VOLTAGE - 0.002f, // current - OBK_CURRENT - 0.25f, // power - OBK_POWER + 0.25f, // voltage - OBK_VOLTAGE + 0.002f, // current - OBK_CURRENT + 0.25f, // power - OBK_POWER }; int changeSendAlwaysFrames = 60; int changeDoNotSendMinFrames = 5; -void BL09XX_AppendInformationToHTTPIndexPage(http_request_t *request) { - char tmp[128]; - const char *mode; +void BL09XX_AppendInformationToHTTPIndexPage(http_request_t *request) +{ + int i; + char tmp[128]; + const char *mode; + char number[16]; - if(DRV_IsRunning("BL0937")) { - mode = "BL0937"; - } else if(DRV_IsRunning("BL0942")) { - mode = "BL0942"; - } else { - mode = "PWR"; - } - sprintf(tmp, "

%s Voltage=%f, Current=%f, Power=%f, Consumption=%f (changes sent %i, skipped %i)

", - mode, lastReadings[OBK_VOLTAGE],lastReadings[OBK_CURRENT], lastReadings[OBK_POWER], + if(DRV_IsRunning("BL0937")) { + mode = "BL0937"; + } else if(DRV_IsRunning("BL0942")) { + mode = "BL0942"; + } else { + mode = "PWR"; + } + sprintf(tmp, "

%s Voltage=%f, Current=%f, Power=%f, Consumption=%1.1f Wh (changes sent %i, skipped %i)

", + mode, lastReadings[OBK_VOLTAGE],lastReadings[OBK_CURRENT], lastReadings[OBK_POWER], energyCounter, stat_updatesSent, stat_updatesSkipped); hprintf128(request,tmp); + /********************************************************************************************************************/ + sprintf(tmp, "

Last Hour Statistics

Consumption: %1.1f Wh
", DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR)); + hprintf128(request,tmp); + sprintf(tmp, "History per minute:
"); + hprintf128(request,tmp); + memset(tmp,0,128); + for(i=0; i<60; i++) + { + if ((i%20)==0) + { + sprintf(number,"%1.1f", energyCounterMinutes[i]); + } else { + sprintf(number,", %1.1f", energyCounterMinutes[i]); + } + strcat(tmp, number); + if ((i%20)==19) + { + strcat(tmp, "
"); + hprintf128(request,tmp); + memset(tmp,0,128); + } + } + hprintf128(request,"History Index: %d
", energyCounterMinutesIndex); + /********************************************************************************************************************/ } int BL0937_ResetEnergyCounter(const void *context, const char *cmd, const char *args, int cmdFlags) { float value; + int i; if(args==0||*args==0) { energyCounter = 0.0f; energyCounterStamp = xTaskGetTickCount(); + for(i = 0; i < 60; i++) + { + energyCounterMinutes[i] = 0.0; + } + energyCounterMinutesStamp = xTaskGetTickCount(); + energyCounterMinutesIndex = 0; } else { value = atof(args); energyCounter = value; @@ -81,14 +121,18 @@ int BL0937_ResetEnergyCounter(const void *context, const char *cmd, const char * void BL_ProcessUpdate(float voltage, float current, float power) { - int i; + int i; float energy; int xPassedTicks; + cJSON* root; + cJSON* stats; + char *msg; + // those are final values, like 230V - lastReadings[OBK_POWER] = power; - lastReadings[OBK_VOLTAGE] = voltage; - lastReadings[OBK_CURRENT] = current; + lastReadings[OBK_POWER] = power; + lastReadings[OBK_VOLTAGE] = voltage; + lastReadings[OBK_CURRENT] = current; xPassedTicks = (int)(xTaskGetTickCount() - energyCounterStamp); if (xPassedTicks <= 0) @@ -100,65 +144,132 @@ void BL_ProcessUpdate(float voltage, float current, float power) energyCounter += energy; energyCounterStamp = xTaskGetTickCount(); - for(i = 0; i < OBK_NUM_MEASUREMENTS; i++) + if ((xTaskGetTickCount() - energyCounterMinutesStamp) >= (60000 / portTICK_PERIOD_MS)) { - // send update only if there was a big change or if certain time has passed - // Do not send message with every measurement. - if ( ((abs(lastSentValues[i]-lastReadings[i]) > changeSendThresholds[i]) && - (noChangeFrames[i] >= changeDoNotSendMinFrames)) || - (noChangeFrames[i] >= changeSendAlwaysFrames) ) + root = cJSON_CreateObject(); + cJSON_AddNumberToObject(root, "uptime", Time_getUpTimeSeconds()); + cJSON_AddNumberToObject(root, "consumption_total", energyCounter ); + cJSON_AddNumberToObject(root, "consumption_last_hour", DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR)); + cJSON_AddNumberToObject(root, "consumption_stat_index", energyCounterMinutesIndex); + + stats = cJSON_CreateArray(); + for(i = 0; i < 60; i++) { - noChangeFrames[i] = 0; - if(i == OBK_CURRENT) + cJSON_AddItemToArray(stats, cJSON_CreateNumber(energyCounterMinutes[i])); + } + cJSON_AddItemToObject(root, "consumption_minutes", stats); + + msg = cJSON_Print(root); + cJSON_Delete(root); + + MQTT_PublishMain_StringString(counter_mqttNames[2], msg, 0); + stat_updatesSent++; + os_free(msg); + + for (i=59;i>0;i--) + { + energyCounterMinutes[i] = energyCounterMinutes[i-1]; + } + energyCounterMinutes[0] = 0.0; + energyCounterMinutesStamp = xTaskGetTickCount(); + energyCounterMinutesIndex++; + + MQTT_PublishMain_StringFloat(counter_mqttNames[1], DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR)); + EventHandlers_ProcessVariableChange_Integer(CMD_EVENT_CHANGE_CONSUMPTION_LAST_HOUR, lastSentEnergyCounterLastHour, DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR)); + lastSentEnergyCounterLastHour = DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR); + stat_updatesSent++; + } + energyCounterMinutes[0] += energy; + + for(i = 0; i < OBK_NUM_MEASUREMENTS; i++) + { + // send update only if there was a big change or if certain time has passed + // Do not send message with every measurement. + if ( ((abs(lastSentValues[i]-lastReadings[i]) > changeSendThresholds[i]) && + (noChangeFrames[i] >= changeDoNotSendMinFrames)) || + (noChangeFrames[i] >= changeSendAlwaysFrames) ) + { + noChangeFrames[i] = 0; + if(i == OBK_CURRENT) { - int prev_mA, now_mA; - prev_mA = lastSentValues[i] * 1000; - now_mA = lastReadings[i] * 1000; - EventHandlers_ProcessVariableChange_Integer(CMD_EVENT_CHANGE_CURRENT, prev_mA,now_mA); - } else { - EventHandlers_ProcessVariableChange_Integer(CMD_EVENT_CHANGE_VOLTAGE+i, lastSentValues[i], lastReadings[i]); - } - lastSentValues[i] = lastReadings[i]; - MQTT_PublishMain_StringFloat(sensor_mqttNames[i],lastReadings[i]); - stat_updatesSent++; - } else { - // no change frame - noChangeFrames[i]++; - stat_updatesSkipped++; - } + int prev_mA, now_mA; + prev_mA = lastSentValues[i] * 1000; + now_mA = lastReadings[i] * 1000; + EventHandlers_ProcessVariableChange_Integer(CMD_EVENT_CHANGE_CURRENT, prev_mA,now_mA); + } else { + EventHandlers_ProcessVariableChange_Integer(CMD_EVENT_CHANGE_VOLTAGE+i, lastSentValues[i], lastReadings[i]); + } + lastSentValues[i] = lastReadings[i]; + MQTT_PublishMain_StringFloat(sensor_mqttNames[i],lastReadings[i]); + stat_updatesSent++; + } else { + // no change frame + noChangeFrames[i]++; + stat_updatesSkipped++; + } } if ( (((energyCounter - lastSentEnergyCounterValue) >= changeSendThresholdEnergy) && (noChangeFrameEnergyCounter >= changeDoNotSendMinFrames)) || (noChangeFrameEnergyCounter >= changeSendAlwaysFrames) ) { + MQTT_PublishMain_StringFloat(counter_mqttNames[0], energyCounter); + EventHandlers_ProcessVariableChange_Integer(CMD_EVENT_CHANGE_CONSUMPTION_TOTAL, lastSentEnergyCounterValue, energyCounter); lastSentEnergyCounterValue = energyCounter; - MQTT_PublishMain_StringFloat("energycounter", energyCounter); noChangeFrameEnergyCounter = 0; stat_updatesSent++; + MQTT_PublishMain_StringFloat(counter_mqttNames[1], DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR)); + EventHandlers_ProcessVariableChange_Integer(CMD_EVENT_CHANGE_CONSUMPTION_LAST_HOUR, lastSentEnergyCounterLastHour, DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR)); + lastSentEnergyCounterLastHour = DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR); + stat_updatesSent++; } else { noChangeFrameEnergyCounter++; stat_updatesSkipped++; } } -void BL_Shared_Init() +void BL_Shared_Init() { - int i; + int i; - for(i = 0; i < OBK_NUM_MEASUREMENTS; i++) + for(i = 0; i < OBK_NUM_MEASUREMENTS; i++) { - noChangeFrames[i] = 0; - lastReadings[i] = 0; - } + noChangeFrames[i] = 0; + lastReadings[i] = 0; + } noChangeFrameEnergyCounter = 0; energyCounterStamp = xTaskGetTickCount(); + + for(i = 0; i < 60; i++) + { + energyCounterMinutes[i] = 0.0; + } + energyCounterMinutesStamp = xTaskGetTickCount(); + energyCounterMinutesIndex = 0; } // OBK_POWER etc float DRV_GetReading(int type) { - return lastReadings[type]; + int i; + float hourly_sum = 0.0; + switch (type) + { + case OBK_VOLTAGE: // must match order in cmd_public.h + case OBK_CURRENT: + case OBK_POWER: + return lastReadings[type]; + case OBK_CONSUMPTION_TOTAL: + return energyCounter; + case OBK_CONSUMPTION_LAST_HOUR: + for(i=0;i<60;i++) + { + hourly_sum += energyCounterMinutes[i]; + } + return hourly_sum; + default: + break; + } + return 0.0f; } - diff --git a/src/driver/drv_main.c b/src/driver/drv_main.c index ddec5d081..6d428a945 100644 --- a/src/driver/drv_main.c +++ b/src/driver/drv_main.c @@ -18,6 +18,12 @@ const char *sensor_mqttNames[OBK_NUM_MEASUREMENTS] = { "power" }; +const char *counter_mqttNames[OBK_NUM_COUNTERS] = { + "energycounter", + "energycounter_last_hour", + "consumption_stats" +}; + typedef struct driver_s { const char *name; void (*initFunc)(); @@ -54,7 +60,7 @@ static driver_t g_drivers[] = { { "tmSensor", TuyaMCU_Sensor_Init, TuyaMCU_Sensor_RunFrame, NULL, NULL, NULL, NULL, false } }; -static int g_numDrivers = sizeof(g_drivers)/sizeof(g_drivers[0]); +static const int g_numDrivers = sizeof(g_drivers)/sizeof(g_drivers[0]); bool DRV_IsRunning(const char *name) { int i; @@ -144,7 +150,7 @@ void DRV_StopDriver(const char *name) { if(g_drivers[i].stopFunc != 0) { g_drivers[i].stopFunc(); } - g_drivers[i].bLoaded = 0; + g_drivers[i].bLoaded = false; addLogAdv(LOG_INFO, LOG_FEATURE_NTP,"Drv %s has been stopped.\n",name); break ; } else { diff --git a/src/driver/drv_public.h b/src/driver/drv_public.h index 490ec5591..afe85c19b 100644 --- a/src/driver/drv_public.h +++ b/src/driver/drv_public.h @@ -9,8 +9,19 @@ enum { OBK_NUM_MEASUREMENTS, }; +enum { + OBK_CONSUMPTION_TOTAL = OBK_NUM_MEASUREMENTS, + OBK_CONSUMPTION_LAST_HOUR, + OBK_CONSUMPTION_STATS, + OBK_NUM_EMUNS_MAX +}; + +#define OBK_NUM_COUNTERS (OBK_NUM_EMUNS_MAX-OBK_NUM_MEASUREMENTS) +#define OBK_NUM_SENSOR_COUNT OBK_NUM_EMUNS_MAX + // MQTT names of sensors (voltage, current, power) extern const char *sensor_mqttNames[]; +extern const char *counter_mqttNames[]; void DRV_Generic_Init(); void DRV_AppendInformationToHTTPIndexPage(http_request_t *request); diff --git a/src/driver/drv_tuyaMCU.c b/src/driver/drv_tuyaMCU.c index 3a5adf011..9f4be84ba 100644 --- a/src/driver/drv_tuyaMCU.c +++ b/src/driver/drv_tuyaMCU.c @@ -52,19 +52,19 @@ void TuyaMCU_RunFrame(); const char *TuyaMCU_GetDataTypeString(int dpId){ - if(DP_TYPE_RAW == dpId) - return "DP_TYPE_RAW"; - if(DP_TYPE_BOOL == dpId) - return "DP_TYPE_BOOL"; - if(DP_TYPE_VALUE == dpId) - return "DP_TYPE_VALUE"; - if(DP_TYPE_STRING == dpId) - return "DP_TYPE_STRING"; - if(DP_TYPE_ENUM == dpId) - return "DP_TYPE_ENUM"; - if(DP_TYPE_BITMAP == dpId) - return "DP_TYPE_BITMAP"; - return "DP_ERROR"; + if(DP_TYPE_RAW == dpId) + return "DP_TYPE_RAW"; + if(DP_TYPE_BOOL == dpId) + return "DP_TYPE_BOOL"; + if(DP_TYPE_VALUE == dpId) + return "DP_TYPE_VALUE"; + if(DP_TYPE_STRING == dpId) + return "DP_TYPE_STRING"; + if(DP_TYPE_ENUM == dpId) + return "DP_TYPE_ENUM"; + if(DP_TYPE_BITMAP == dpId) + return "DP_TYPE_BITMAP"; + return "DP_ERROR"; } // from http_fns. should move to a utils file. extern unsigned char hexbyte( const char* hex ); @@ -73,55 +73,55 @@ extern unsigned char hexbyte( const char* hex ); const char *TuyaMCU_GetCommandTypeLabel(int t) { - if(t == TUYA_CMD_HEARTBEAT) - return "Hearbeat"; - if(t == TUYA_CMD_QUERY_PRODUCT) - return "QueryProductInformation"; - if(t == TUYA_CMD_MCU_CONF) - return "MCUconf"; - if(t == TUYA_CMD_WIFI_STATE) - return "WiFiState"; - if(t == TUYA_CMD_WIFI_RESET) - return "WiFiReset"; - if(t == TUYA_CMD_WIFI_SELECT) - return "WiFiSelect"; - if(t == TUYA_CMD_SET_DP) - return "SetDP"; - if(t == TUYA_CMD_STATE) - return "State"; - if(t == TUYA_CMD_QUERY_STATE) - return "QueryState"; - if(t == TUYA_CMD_SET_TIME) - return "SetTime"; - return "Unknown"; + if(t == TUYA_CMD_HEARTBEAT) + return "Hearbeat"; + if(t == TUYA_CMD_QUERY_PRODUCT) + return "QueryProductInformation"; + if(t == TUYA_CMD_MCU_CONF) + return "MCUconf"; + if(t == TUYA_CMD_WIFI_STATE) + return "WiFiState"; + if(t == TUYA_CMD_WIFI_RESET) + return "WiFiReset"; + if(t == TUYA_CMD_WIFI_SELECT) + return "WiFiSelect"; + if(t == TUYA_CMD_SET_DP) + return "SetDP"; + if(t == TUYA_CMD_STATE) + return "State"; + if(t == TUYA_CMD_QUERY_STATE) + return "QueryState"; + if(t == TUYA_CMD_SET_TIME) + return "SetTime"; + return "Unknown"; } typedef struct rtcc_s { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t day_of_week; // sunday is day 1 - uint8_t day_of_month; - uint8_t month; - char name_of_month[4]; - uint16_t day_of_year; - uint16_t year; - uint32_t days; - uint32_t valid; + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t day_of_week; // sunday is day 1 + uint8_t day_of_month; + uint8_t month; + char name_of_month[4]; + uint16_t day_of_year; + uint16_t year; + uint32_t days; + uint32_t valid; } rtcc_t; typedef struct tuyaMCUMapping_s { - // internal Tuya variable index - int fnId; - // target channel - int channel; - // data point type (one of the DP_TYPE_xxx defines) - int dpType; - // store last channel value to avoid sending it again - int prevValue; - // TODO - //int mode; - // list - struct tuyaMCUMapping_s *next; + // internal Tuya variable index + int fnId; + // target channel + int channel; + // data point type (one of the DP_TYPE_xxx defines) + int dpType; + // store last channel value to avoid sending it again + int prevValue; + // TODO + //int mode; + // list + struct tuyaMCUMapping_s *next; } tuyaMCUMapping_t; tuyaMCUMapping_t *g_tuyaMappings = 0; @@ -140,119 +140,130 @@ int g_dimmerRangeMax = 100; // serial baud rate used to communicate with the TuyaMCU int g_baudRate = 9600; -tuyaMCUMapping_t *TuyaMCU_FindDefForID(int fnId) { - tuyaMCUMapping_t *cur; +static bool heartbeat_valid = false; +static int heartbeat_timer = 0; +static int heartbeat_counter = 0; +static bool product_information_valid = false; +static char *prod_info = NULL; +static bool working_mode_valid = false; +static bool wifi_state_valid = false; +static bool wifi_state = false; +static bool self_processing_mode = true; +static bool state_updated = false; - cur = g_tuyaMappings; - while(cur) { - if(cur->fnId == fnId) - return cur; - cur = cur->next; - } - return 0; +tuyaMCUMapping_t *TuyaMCU_FindDefForID(int fnId) { + tuyaMCUMapping_t *cur; + + cur = g_tuyaMappings; + while(cur) { + if(cur->fnId == fnId) + return cur; + cur = cur->next; + } + return 0; } tuyaMCUMapping_t *TuyaMCU_FindDefForChannel(int channel) { - tuyaMCUMapping_t *cur; + tuyaMCUMapping_t *cur; - cur = g_tuyaMappings; - while(cur) { - if(cur->channel == channel) - return cur; - cur = cur->next; - } - return 0; + cur = g_tuyaMappings; + while(cur) { + if(cur->channel == channel) + return cur; + cur = cur->next; + } + return 0; } void TuyaMCU_MapIDToChannel(int fnId, int dpType, int channel) { - tuyaMCUMapping_t *cur; + tuyaMCUMapping_t *cur; - cur = TuyaMCU_FindDefForID(fnId); + cur = TuyaMCU_FindDefForID(fnId); - if(cur == 0) { - cur = (tuyaMCUMapping_t*)malloc(sizeof(tuyaMCUMapping_t)); - cur->fnId = fnId; - cur->dpType = dpType; - cur->prevValue = 0; - cur->next = g_tuyaMappings; - g_tuyaMappings = cur; - } + if(cur == 0) { + cur = (tuyaMCUMapping_t*)malloc(sizeof(tuyaMCUMapping_t)); + cur->fnId = fnId; + cur->dpType = dpType; + cur->prevValue = 0; + cur->next = g_tuyaMappings; + g_tuyaMappings = cur; + } - cur->channel = channel; + cur->channel = channel; } // header version command lenght data checksum -// 55AA 00 00 0000 xx 00 +// 55AA 00 00 0000 xx 00 #define MIN_TUYAMCU_PACKET_SIZE (2+1+1+2+1) int UART_TryToGetNextTuyaPacket(byte *out, int maxSize) { - int cs; - int len, i; - int c_garbage_consumed = 0; - byte a, b, version, command, lena, lenb; - char printfSkipDebug[256]; - char buffer2[8]; + int cs; + int len, i; + int c_garbage_consumed = 0; + byte a, b, version, command, lena, lenb; + char printfSkipDebug[256]; + char buffer2[8]; - printfSkipDebug[0] = 0; + printfSkipDebug[0] = 0; - cs = UART_GetDataSize(); + cs = UART_GetDataSize(); - if(cs < MIN_TUYAMCU_PACKET_SIZE) { - return 0; - } - // skip garbage data (should not happen) - while(cs > 0) { - a = UART_GetNextByte(0); - b = UART_GetNextByte(1); - if(a != 0x55 || b != 0xAA) { - UART_ConsumeBytes(1); - if(c_garbage_consumed + 2 < sizeof(printfSkipDebug)) { - sprintf(buffer2,"%02X ",a); - strcat_safe(printfSkipDebug,buffer2,sizeof(printfSkipDebug)); - } - c_garbage_consumed++; - cs--; - } else { - break; - } - } - if(c_garbage_consumed > 0){ - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"Consumed %i unwanted non-header byte in Tuya MCU buffer\n", c_garbage_consumed); - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"Skipped data (part) %s\n", printfSkipDebug); - } - if(cs < MIN_TUYAMCU_PACKET_SIZE) { - return 0; - } - a = UART_GetNextByte(0); - b = UART_GetNextByte(1); - if(a != 0x55 || b != 0xAA) { - return 0; - } - version = UART_GetNextByte(2); - command = UART_GetNextByte(3); - lena = UART_GetNextByte(4); // hi - lenb = UART_GetNextByte(5); // lo - len = lenb | lena >> 8; - // now check if we have received whole packet - len += 2 + 1 + 1 + 2 + 1; // header 2 bytes, version, command, lenght, chekcusm - if(cs >= len) { - int ret; - // can packet fit into the buffer? - if(len <= maxSize) { - for(i = 0; i < len; i++) { - out[i] = UART_GetNextByte(i); - } - ret = len; - } else { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU packet too large, %i > %i\n", len, maxSize); - ret = 0; - } - // consume whole packet (but don't touch next one, if any) - UART_ConsumeBytes(len); - return ret; - } - return 0; + if(cs < MIN_TUYAMCU_PACKET_SIZE) { + return 0; + } + // skip garbage data (should not happen) + while(cs > 0) { + a = UART_GetNextByte(0); + b = UART_GetNextByte(1); + if(a != 0x55 || b != 0xAA) { + UART_ConsumeBytes(1); + if(c_garbage_consumed + 2 < sizeof(printfSkipDebug)) { + sprintf(buffer2,"%02X ",a); + strcat_safe(printfSkipDebug,buffer2,sizeof(printfSkipDebug)); + } + c_garbage_consumed++; + cs--; + } else { + break; + } + } + if(c_garbage_consumed > 0){ + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"Consumed %i unwanted non-header byte in Tuya MCU buffer\n", c_garbage_consumed); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"Skipped data (part) %s\n", printfSkipDebug); + } + if(cs < MIN_TUYAMCU_PACKET_SIZE) { + return 0; + } + a = UART_GetNextByte(0); + b = UART_GetNextByte(1); + if(a != 0x55 || b != 0xAA) { + return 0; + } + version = UART_GetNextByte(2); + command = UART_GetNextByte(3); + lena = UART_GetNextByte(4); // hi + lenb = UART_GetNextByte(5); // lo + len = lenb | lena >> 8; + // now check if we have received whole packet + len += 2 + 1 + 1 + 2 + 1; // header 2 bytes, version, command, lenght, chekcusm + if(cs >= len) { + int ret; + // can packet fit into the buffer? + if(len <= maxSize) { + for(i = 0; i < len; i++) { + out[i] = UART_GetNextByte(i); + } + ret = len; + } else { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU packet too large, %i > %i\n", len, maxSize); + ret = 0; + } + // consume whole packet (but don't touch next one, if any) + UART_ConsumeBytes(len); + return ret; + } + return 0; } @@ -260,22 +271,22 @@ int UART_TryToGetNextTuyaPacket(byte *out, int maxSize) { // append header, len, everything, checksum void TuyaMCU_SendCommandWithData(byte cmdType, byte *data, int payload_len) { - int i; + int i; - byte check_sum = (0xFF + cmdType + (payload_len >> 8) + (payload_len & 0xFF)); - UART_InitUART(g_baudRate); - UART_SendByte(0x55); - UART_SendByte(0xAA); - UART_SendByte(0x00); // version 00 - UART_SendByte(cmdType); // version 00 - UART_SendByte(payload_len >> 8); // following data length (Hi) - UART_SendByte(payload_len & 0xFF); // following data length (Lo) - for(i = 0; i < payload_len; i++) { - byte b = data[i]; - check_sum += b; - UART_SendByte(b); - } - UART_SendByte(check_sum); + byte check_sum = (0xFF + cmdType + (payload_len >> 8) + (payload_len & 0xFF)); + UART_InitUART(g_baudRate); + UART_SendByte(0x55); + UART_SendByte(0xAA); + UART_SendByte(0x00); // version 00 + UART_SendByte(cmdType); // version 00 + UART_SendByte(payload_len >> 8); // following data length (Hi) + UART_SendByte(payload_len & 0xFF); // following data length (Lo) + for(i = 0; i < payload_len; i++) { + byte b = data[i]; + check_sum += b; + UART_SendByte(b); + } + UART_SendByte(check_sum); } void TuyaMCU_SendState(uint8_t id, uint8_t type, uint8_t* value) @@ -397,72 +408,72 @@ void TuyaMCU_SendRaw(uint8_t id, char data[]) { } void TuyaMCU_Send_SetTime(struct tm *pTime) { - byte payload_buffer[8]; - byte tuya_day_of_week; + byte payload_buffer[8]; + byte tuya_day_of_week; - if (pTime->tm_wday == 1) { - tuya_day_of_week = 7; - } else { - tuya_day_of_week = pTime->tm_wday-1; - } + if (pTime->tm_wday == 1) { + tuya_day_of_week = 7; + } else { + tuya_day_of_week = pTime->tm_wday-1; + } - payload_buffer[0] = 0x01; - payload_buffer[1] = pTime->tm_year % 100; - payload_buffer[2] = pTime->tm_mon; - payload_buffer[3] = pTime->tm_mday; - payload_buffer[4] = pTime->tm_hour; - payload_buffer[5] = pTime->tm_min; - payload_buffer[6] = pTime->tm_sec; - payload_buffer[7] = tuya_day_of_week; //1 for Monday in TUYA Doc + payload_buffer[0] = 0x01; + payload_buffer[1] = pTime->tm_year % 100; + payload_buffer[2] = pTime->tm_mon; + payload_buffer[3] = pTime->tm_mday; + payload_buffer[4] = pTime->tm_hour; + payload_buffer[5] = pTime->tm_min; + payload_buffer[6] = pTime->tm_sec; + payload_buffer[7] = tuya_day_of_week; //1 for Monday in TUYA Doc - TuyaMCU_SendCommandWithData(TUYA_CMD_SET_TIME, payload_buffer, 8); + TuyaMCU_SendCommandWithData(TUYA_CMD_SET_TIME, payload_buffer, 8); } struct tm * TuyaMCU_Get_NTP_Time() { - int g_time; - struct tm * ptm; + int g_time; + struct tm * ptm; - g_time = NTP_GetCurrentTime(); - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"MCU time to set: %i\n", g_time); - ptm = gmtime(&g_time); - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"ptime ->gmtime => tm_hour: %i\n",ptm->tm_hour ); - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"ptime ->gmtime => tm_min: %i\n", ptm->tm_min ); + g_time = NTP_GetCurrentTime(); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"MCU time to set: %i\n", g_time); + ptm = gmtime(&g_time); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"ptime ->gmtime => tm_hour: %i\n",ptm->tm_hour ); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"ptime ->gmtime => tm_min: %i\n", ptm->tm_min ); - return ptm; + return ptm; } // int TuyaMCU_Fake_Hex(const void *context, const char *cmd, const char *args, int cmdFlags) { - //const char *args = CMD_GetArg(1); - //byte rawData[128]; - //int curCnt; + //const char *args = CMD_GetArg(1); + //byte rawData[128]; + //int curCnt; - //curCnt = 0; - if(!(*args)) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_Fake_Hex: requires 1 argument (hex string, like FFAABB00CCDD\n"); - return -1; - } - while(*args) { - byte b; - b = hexbyte(args); + //curCnt = 0; + if(!(*args)) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_Fake_Hex: requires 1 argument (hex string, like FFAABB00CCDD\n"); + return -1; + } + while(*args) { + byte b; + b = hexbyte(args); - //rawData[curCnt] = b; - //curCnt++; - //if(curCnt>=sizeof(rawData)) { - // addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_Fake_Hex: sorry, given string is too long\n"); - // return -1; - //} + //rawData[curCnt] = b; + //curCnt++; + //if(curCnt>=sizeof(rawData)) { + // addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_Fake_Hex: sorry, given string is too long\n"); + // return -1; + //} - UART_AppendByteToCircularBuffer(b); + UART_AppendByteToCircularBuffer(b); - args += 2; - } - return 1; + args += 2; + } + return 1; } void TuyaMCU_Send_RawBuffer(byte *data, int len) { - int i; + int i; - for(i = 0; i < len; i++) { - UART_SendByte(data[i]); - } + for(i = 0; i < len; i++) { + UART_SendByte(data[i]); + } } //battery-powered water sensor with TyuaMCU request to get somo response // uartSendHex 55AA0001000000 - this will get reply: @@ -483,155 +494,160 @@ Info:GEN:No change in channel 1 (still set to 0) - ignoring */ int TuyaMCU_Send_Hex(const void *context, const char *cmd, const char *args, int cmdFlags) { - //const char *args = CMD_GetArg(1); - if(!(*args)) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_Send_Hex: requires 1 argument (hex string, like FFAABB00CCDD\n"); - return -1; - } - while(*args) { - byte b; - b = hexbyte(args); + //const char *args = CMD_GetArg(1); + if(!(*args)) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_Send_Hex: requires 1 argument (hex string, like FFAABB00CCDD\n"); + return -1; + } + while(*args) { + byte b; + b = hexbyte(args); - UART_SendByte(b); + UART_SendByte(b); - args += 2; - } - return 1; + args += 2; + } + return 1; } int TuyaMCU_LinkTuyaMCUOutputToChannel(const void *context, const char *cmd, const char *args, int cmdFlags) { - int dpId; - const char *dpTypeString; - int dpType; - int channelID; + int dpId; + const char *dpTypeString; + int dpType; + int channelID; - // linkTuyaMCUOutputToChannel dpId varType channelID - // linkTuyaMCUOutputToChannel 1 val 1 - Tokenizer_TokenizeString(args); + // linkTuyaMCUOutputToChannel dpId varType channelID + // linkTuyaMCUOutputToChannel 1 val 1 + Tokenizer_TokenizeString(args); - if(Tokenizer_GetArgsCount() < 3) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_LinkTuyaMCUOutputToChannel: requires 3 arguments (dpId, dpType, channelIndex)\n"); - return -1; - } - dpId = Tokenizer_GetArgInteger(0); - dpTypeString = Tokenizer_GetArg(1); - if(!stricmp(dpTypeString,"bool")) { - dpType = DP_TYPE_BOOL; - } else if(!stricmp(dpTypeString,"val")) { - dpType = DP_TYPE_VALUE; - } else if(!stricmp(dpTypeString,"str")) { - dpType = DP_TYPE_STRING; - } else if(!stricmp(dpTypeString,"enum")) { - dpType = DP_TYPE_ENUM; - } else if(!stricmp(dpTypeString,"raw")) { - dpType = DP_TYPE_RAW; - } else { - if(strIsInteger(dpTypeString)) { - dpType = atoi(dpTypeString); - } else { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_LinkTuyaMCUOutputToChannel: %s is not a valid var type\n",dpTypeString); - return -1; - } - } - channelID = Tokenizer_GetArgInteger(2); + if(Tokenizer_GetArgsCount() < 3) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_LinkTuyaMCUOutputToChannel: requires 3 arguments (dpId, dpType, channelIndex)\n"); + return -1; + } + dpId = Tokenizer_GetArgInteger(0); + dpTypeString = Tokenizer_GetArg(1); + if(!stricmp(dpTypeString,"bool")) { + dpType = DP_TYPE_BOOL; + } else if(!stricmp(dpTypeString,"val")) { + dpType = DP_TYPE_VALUE; + } else if(!stricmp(dpTypeString,"str")) { + dpType = DP_TYPE_STRING; + } else if(!stricmp(dpTypeString,"enum")) { + dpType = DP_TYPE_ENUM; + } else if(!stricmp(dpTypeString,"raw")) { + dpType = DP_TYPE_RAW; + } else { + if(strIsInteger(dpTypeString)) { + dpType = atoi(dpTypeString); + } else { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_LinkTuyaMCUOutputToChannel: %s is not a valid var type\n",dpTypeString); + return -1; + } + } + channelID = Tokenizer_GetArgInteger(2); - TuyaMCU_MapIDToChannel(dpId, dpType, channelID); + TuyaMCU_MapIDToChannel(dpId, dpType, channelID); - return 1; + return 1; } int TuyaMCU_Send_SetTime_Current(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_Send_SetTime(TuyaMCU_Get_NTP_Time()); + TuyaMCU_Send_SetTime(TuyaMCU_Get_NTP_Time()); - return 1; + return 1; } int TuyaMCU_Send_SetTime_Example(const void *context, const char *cmd, const char *args, int cmdFlags) { - struct tm testTime; + struct tm testTime; - testTime.tm_year = 2012; - testTime.tm_mon = 7; - testTime.tm_mday = 15; - testTime.tm_wday = 4; - testTime.tm_hour = 6; - testTime.tm_min = 54; - testTime.tm_sec = 32; + testTime.tm_year = 2012; + testTime.tm_mon = 7; + testTime.tm_mday = 15; + testTime.tm_wday = 4; + testTime.tm_hour = 6; + testTime.tm_min = 54; + testTime.tm_sec = 32; - TuyaMCU_Send_SetTime(&testTime); - return 1; + TuyaMCU_Send_SetTime(&testTime); + return 1; } void TuyaMCU_Send(byte *data, int size) { - int i; + int i; unsigned char check_sum; - check_sum = 0; - for(i = 0; i < size; i++) { - byte b = data[i]; - check_sum += b; - UART_SendByte(b); - } - UART_SendByte(check_sum); + check_sum = 0; + for(i = 0; i < size; i++) { + byte b = data[i]; + check_sum += b; + UART_SendByte(b); + } + UART_SendByte(check_sum); - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"\nWe sent %i bytes to Tuya MCU\n",size+1); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"\nWe sent %i bytes to Tuya MCU\n",size+1); } int TuyaMCU_SetDimmerRange(const void *context, const char *cmd, const char *args, int cmdFlags) { - Tokenizer_TokenizeString(args); + Tokenizer_TokenizeString(args); - if(Tokenizer_GetArgsCount() < 2) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"tuyaMcu_setDimmerRange: requires 2 arguments (dimmerRangeMin, dimmerRangeMax)\n"); - return -1; - } + if(Tokenizer_GetArgsCount() < 2) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"tuyaMcu_setDimmerRange: requires 2 arguments (dimmerRangeMin, dimmerRangeMax)\n"); + return -1; + } - g_dimmerRangeMin = Tokenizer_GetArgInteger(0); - g_dimmerRangeMax = Tokenizer_GetArgInteger(1); + g_dimmerRangeMin = Tokenizer_GetArgInteger(0); + g_dimmerRangeMax = Tokenizer_GetArgInteger(1); - return 1; + return 1; } int TuyaMCU_SendHeartbeat(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_HEARTBEAT, NULL, 0); + TuyaMCU_SendCommandWithData(TUYA_CMD_HEARTBEAT, NULL, 0); - return 1; + return 1; } int TuyaMCU_SendQueryProductInformation(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_PRODUCT, NULL, 0); + TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_PRODUCT, NULL, 0); - return 1; + return 1; } int TuyaMCU_SendQueryState(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_STATE, NULL, 0); + TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_STATE, NULL, 0); - return 1; + return 1; } int TuyaMCU_SendStateCmd(const void *context, const char *cmd, const char *args, int cmdFlags) { - int dpId; - int dpType; - int value; + int dpId; + int dpType; + int value; - Tokenizer_TokenizeString(args); + Tokenizer_TokenizeString(args); - if(Tokenizer_GetArgsCount() < 3) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"tuyaMcu_sendState: requires 3 arguments (dpId, dpType, value)\n"); - return -1; - } + if(Tokenizer_GetArgsCount() < 3) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"tuyaMcu_sendState: requires 3 arguments (dpId, dpType, value)\n"); + return -1; + } - dpId = Tokenizer_GetArgInteger(0); - dpType = Tokenizer_GetArgInteger(1); - value = Tokenizer_GetArgInteger(2); + dpId = Tokenizer_GetArgInteger(0); + dpType = Tokenizer_GetArgInteger(1); + value = Tokenizer_GetArgInteger(2); - TuyaMCU_SendState(dpId, dpType, (uint8_t *)&value); + TuyaMCU_SendState(dpId, dpType, (uint8_t *)&value); - return 1; + return 1; } int TuyaMCU_SendMCUConf(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_MCU_CONF, NULL, 0); + TuyaMCU_SendCommandWithData(TUYA_CMD_MCU_CONF, NULL, 0); - return 1; + return 1; +} + +void Tuya_SetWifiState(uint8_t state) +{ + TuyaMCU_SendCommandWithData(TUYA_CMD_WIFI_STATE, &state, 1); } // ntp_timeZoneOfs 2 @@ -646,109 +662,109 @@ int TuyaMCU_SendMCUConf(const void *context, const char *cmd, const char *args, // backlog ntp_timeZoneOfs 2; addRepeatingEvent 10 -1 uartSendHex 55AA0008000007; setChannelType 1 temperature_div10; setChannelType 2 humidity; linkTuyaMCUOutputToChannel 1 1; linkTuyaMCUOutputToChannel 2 2; addRepeatingEvent 10 -1 tuyaMcu_sendCurTime // void TuyaMCU_ApplyMapping(int fnID, int value) { - tuyaMCUMapping_t *mapping; - int mappedValue = value; + tuyaMCUMapping_t *mapping; + int mappedValue = value; - // find mapping (where to save received data) - mapping = TuyaMCU_FindDefForID(fnID); + // find mapping (where to save received data) + mapping = TuyaMCU_FindDefForID(fnID); - if(mapping == 0){ - addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU_ApplyMapping: id %i with value %i is not mapped\n", fnID, value); - return; - } + if(mapping == 0){ + addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU_ApplyMapping: id %i with value %i is not mapped\n", fnID, value); + return; + } - // map value depending on channel type - switch(CHANNEL_GetType(mapping->channel)) - { - case ChType_Dimmer: - // map TuyaMCU's dimmer range to OpenBK7231T_App's dimmer range 0..100 - mappedValue = ((value - g_dimmerRangeMin) * 100) / (g_dimmerRangeMax - g_dimmerRangeMin); - break; - case ChType_Dimmer256: - // map TuyaMCU's dimmer range to OpenBK7231T_App's dimmer range 0..256 - mappedValue = ((value - g_dimmerRangeMin) * 256) / (g_dimmerRangeMax - g_dimmerRangeMin); - break; - default: - break; - } + // map value depending on channel type + switch(CHANNEL_GetType(mapping->channel)) + { + case ChType_Dimmer: + // map TuyaMCU's dimmer range to OpenBK7231T_App's dimmer range 0..100 + mappedValue = ((value - g_dimmerRangeMin) * 100) / (g_dimmerRangeMax - g_dimmerRangeMin); + break; + case ChType_Dimmer256: + // map TuyaMCU's dimmer range to OpenBK7231T_App's dimmer range 0..256 + mappedValue = ((value - g_dimmerRangeMin) * 256) / (g_dimmerRangeMax - g_dimmerRangeMin); + break; + default: + break; + } - if (value != mappedValue) { - addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU_ApplyMapping: mapped value %d (TuyaMCU range) to %d (OpenBK7321T_App range)\n", value, mappedValue); - } + if (value != mappedValue) { + addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU_ApplyMapping: mapped value %d (TuyaMCU range) to %d (OpenBK7321T_App range)\n", value, mappedValue); + } - mapping->prevValue = mappedValue; + mapping->prevValue = mappedValue; - CHANNEL_Set(mapping->channel,mappedValue,0); + CHANNEL_Set(mapping->channel,mappedValue,0); } void TuyaMCU_OnChannelChanged(int channel, int iVal) { - tuyaMCUMapping_t *mapping; - int mappediVal = iVal; + tuyaMCUMapping_t *mapping; + int mappediVal = iVal; - // find mapping - mapping = TuyaMCU_FindDefForChannel(channel); + // find mapping + mapping = TuyaMCU_FindDefForChannel(channel); - if(mapping == 0){ - return; - } + if(mapping == 0){ + return; + } - // this might be a callback from CHANNEL_Set in TuyaMCU_ApplyMapping. If we should set exactly the - // same value, skip it - if (mapping->prevValue == iVal) { - return; - } + // this might be a callback from CHANNEL_Set in TuyaMCU_ApplyMapping. If we should set exactly the + // same value, skip it + if (mapping->prevValue == iVal) { + return; + } - // map value depending on channel type - switch(CHANNEL_GetType(mapping->channel)) - { - case ChType_Dimmer: - // map OpenBK7231T_App's dimmer range 0..100 to TuyaMCU's dimmer range - mappediVal = (((g_dimmerRangeMax - g_dimmerRangeMin) * iVal) / 100) + g_dimmerRangeMin; - break; - case ChType_Dimmer256: - // map OpenBK7231T_App's dimmer range 0..256 to TuyaMCU's dimmer range - mappediVal = (((g_dimmerRangeMax - g_dimmerRangeMin) * iVal) / 256) + g_dimmerRangeMin; - break; - default: - break; - } + // map value depending on channel type + switch(CHANNEL_GetType(mapping->channel)) + { + case ChType_Dimmer: + // map OpenBK7231T_App's dimmer range 0..100 to TuyaMCU's dimmer range + mappediVal = (((g_dimmerRangeMax - g_dimmerRangeMin) * iVal) / 100) + g_dimmerRangeMin; + break; + case ChType_Dimmer256: + // map OpenBK7231T_App's dimmer range 0..256 to TuyaMCU's dimmer range + mappediVal = (((g_dimmerRangeMax - g_dimmerRangeMin) * iVal) / 256) + g_dimmerRangeMin; + break; + default: + break; + } - if (iVal != mappediVal) { - addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU_OnChannelChanged: mapped value %d (OpenBK7321T_App range) to %d (TuyaMCU range)\n", iVal, mappediVal); - } + if (iVal != mappediVal) { + addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU_OnChannelChanged: mapped value %d (OpenBK7321T_App range) to %d (TuyaMCU range)\n", iVal, mappediVal); + } - // send value to TuyaMCU - switch(mapping->dpType) - { - case DP_TYPE_BOOL: - TuyaMCU_SendBool(mapping->fnId, mappediVal != 0); - break; + // send value to TuyaMCU + switch(mapping->dpType) + { + case DP_TYPE_BOOL: + TuyaMCU_SendBool(mapping->fnId, mappediVal != 0); + break; - case DP_TYPE_ENUM: - TuyaMCU_SendEnum(mapping->fnId, mappediVal); - break; + case DP_TYPE_ENUM: + TuyaMCU_SendEnum(mapping->fnId, mappediVal); + break; - case DP_TYPE_VALUE: - TuyaMCU_SendValue(mapping->fnId, mappediVal); - break; + case DP_TYPE_VALUE: + TuyaMCU_SendValue(mapping->fnId, mappediVal); + break; - default: - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_OnChannelChanged: channel %d: unsupported data point type %d-%s\n", channel, mapping->dpType, TuyaMCU_GetDataTypeString(mapping->dpType)); - break; - } + default: + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_OnChannelChanged: channel %d: unsupported data point type %d-%s\n", channel, mapping->dpType, TuyaMCU_GetDataTypeString(mapping->dpType)); + break; + } } void TuyaMCU_ParseQueryProductInformation(const byte *data, int len) { - char name[256]; - int useLen; + char name[256]; + int useLen; - useLen = len-1; - if(useLen > sizeof(name)-1) - useLen = sizeof(name)-1; - memcpy(name,data,useLen); - name[useLen] = 0; + useLen = len-1; + if(useLen > sizeof(name)-1) + useLen = sizeof(name)-1; + memcpy(name,data,useLen); + name[useLen] = 0; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseQueryProductInformation: received %s\n", name); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseQueryProductInformation: received %s\n", name); } // Protocol version - 0x00 (not 0x03) // Used for battery powered devices, eg. door sensor. @@ -756,188 +772,210 @@ void TuyaMCU_ParseQueryProductInformation(const byte *data, int len) { //55AA 00 08 000C 00 02 02 02 02 02 02 01 01 00 01 01 23 -//Head v0 ID lengh bV YY MM DD HH MM SS CHKSUM +//Head v0 ID lengh bV YY MM DD HH MM SS CHKSUM // after that, there are status data uniys -// 01 01 0001 01 -// dpId Type Len Value +// 01 01 0001 01 +// dpId Type Len Value void TuyaMCU_V0_ParseRealTimeWithRecordStorage(const byte *data, int len) { - int ofs; - int sectorLen; - int fnId; - int dataType; + int ofs; + int sectorLen; + int fnId; + int dataType; - //data[0]; // bDateValid - //data[1]; // year - //data[2]; // month - //data[3]; // day - //data[4]; // hour - //data[5]; // minute - //data[6]; // second + //data[0]; // bDateValid + //data[1]; // year + //data[2]; // month + //data[3]; // day + //data[4]; // hour + //data[5]; // minute + //data[6]; // second - ofs = 7; + ofs = 7; - while(ofs + 4 < len) { - sectorLen = data[ofs + 2] << 8 | data[ofs + 3]; - fnId = data[ofs]; - dataType = data[ofs+1]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_V0_ParseRealTimeWithRecordStorage: processing dpId %i, dataType %i-%s and %i data bytes\n", - fnId, dataType, TuyaMCU_GetDataTypeString(dataType),sectorLen); + while(ofs + 4 < len) { + sectorLen = data[ofs + 2] << 8 | data[ofs + 3]; + fnId = data[ofs]; + dataType = data[ofs+1]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_V0_ParseRealTimeWithRecordStorage: processing dpId %i, dataType %i-%s and %i data bytes\n", + fnId, dataType, TuyaMCU_GetDataTypeString(dataType),sectorLen); - if(sectorLen == 1) { - int iVal = (int)data[ofs+4]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_V0_ParseRealTimeWithRecordStorage: raw data 1 byte: %c\n",iVal); - // apply to channels - TuyaMCU_ApplyMapping(fnId,iVal); - } - if(sectorLen == 4) { - int iVal = data[ofs + 4] << 24 | data[ofs + 5] << 16 | data[ofs + 6] << 8 | data[ofs + 7]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_V0_ParseRealTimeWithRecordStorage: raw data 4 int: %i\n",iVal); - // apply to channels - TuyaMCU_ApplyMapping(fnId,iVal); - } + if(sectorLen == 1) { + int iVal = (int)data[ofs+4]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_V0_ParseRealTimeWithRecordStorage: raw data 1 byte: %c\n",iVal); + // apply to channels + TuyaMCU_ApplyMapping(fnId,iVal); + } + if(sectorLen == 4) { + int iVal = data[ofs + 4] << 24 | data[ofs + 5] << 16 | data[ofs + 6] << 8 | data[ofs + 7]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_V0_ParseRealTimeWithRecordStorage: raw data 4 int: %i\n",iVal); + // apply to channels + TuyaMCU_ApplyMapping(fnId,iVal); + } - // size of header (type, datatype, len 2 bytes) + data sector size - ofs += (4+sectorLen); - } + // size of header (type, datatype, len 2 bytes) + data sector size + ofs += (4+sectorLen); + } } void TuyaMCU_ParseStateMessage(const byte *data, int len) { - int ofs; - int sectorLen; - int fnId; - int dataType; + int ofs; + int sectorLen; + int fnId; + int dataType; - ofs = 0; + ofs = 0; - while(ofs + 4 < len) { - sectorLen = data[ofs + 2] << 8 | data[ofs + 3]; - fnId = data[ofs]; - dataType = data[ofs+1]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseStateMessage: processing dpId %i, dataType %i-%s and %i data bytes\n", - fnId, dataType, TuyaMCU_GetDataTypeString(dataType),sectorLen); + while(ofs + 4 < len) { + sectorLen = data[ofs + 2] << 8 | data[ofs + 3]; + fnId = data[ofs]; + dataType = data[ofs+1]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseStateMessage: processing dpId %i, dataType %i-%s and %i data bytes\n", + fnId, dataType, TuyaMCU_GetDataTypeString(dataType),sectorLen); - if(sectorLen == 1) { - int iVal = (int)data[ofs+4]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseStateMessage: raw data 1 byte: %c\n",iVal); - // apply to channels - TuyaMCU_ApplyMapping(fnId,iVal); - } - if(sectorLen == 4) { - int iVal = data[ofs + 4] << 24 | data[ofs + 5] << 16 | data[ofs + 6] << 8 | data[ofs + 7]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseStateMessage: raw data 4 int: %i\n",iVal); - // apply to channels - TuyaMCU_ApplyMapping(fnId,iVal); - } + if(sectorLen == 1) { + int iVal = (int)data[ofs+4]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseStateMessage: raw data 1 byte: %c\n",iVal); + // apply to channels + TuyaMCU_ApplyMapping(fnId,iVal); + } + if(sectorLen == 4) { + int iVal = data[ofs + 4] << 24 | data[ofs + 5] << 16 | data[ofs + 6] << 8 | data[ofs + 7]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ParseStateMessage: raw data 4 int: %i\n",iVal); + // apply to channels + TuyaMCU_ApplyMapping(fnId,iVal); + } - // size of header (type, datatype, len 2 bytes) + data sector size - ofs += (4+sectorLen); - } + // size of header (type, datatype, len 2 bytes) + data sector size + ofs += (4+sectorLen); + } } -#define TUYA_V0_CMD_PRODUCTINFORMATION 0x01 -#define TUYA_V0_CMD_NETWEORKSTATUS 0x02 -#define TUYA_V0_CMD_RESETWIFI 0x03 -#define TUYA_V0_CMD_RESETWIFI_AND_SEL_CONF 0x04 -#define TUYA_V0_CMD_REALTIMESTATUS 0x05 -#define TUYA_V0_CMD_RECORDSTATUS 0x08 +#define TUYA_V0_CMD_PRODUCTINFORMATION 0x01 +#define TUYA_V0_CMD_NETWEORKSTATUS 0x02 +#define TUYA_V0_CMD_RESETWIFI 0x03 +#define TUYA_V0_CMD_RESETWIFI_AND_SEL_CONF 0x04 +#define TUYA_V0_CMD_REALTIMESTATUS 0x05 +#define TUYA_V0_CMD_RECORDSTATUS 0x08 void TuyaMCU_ProcessIncoming(const byte *data, int len) { - int checkLen; - int i; - byte checkCheckSum; - byte cmd; - byte version; + int checkLen; + int i; + byte checkCheckSum; + byte cmd; + byte version; - if(data[0] != 0x55 || data[1] != 0xAA) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: discarding packet with bad ident and len %i\n",len); - return; - } - version = data[2]; - checkLen = data[5] | data[4] >> 8; - checkLen = checkLen + 2 + 1 + 1 + 2 + 1; - if(checkLen != len) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: discarding packet bad expected len, expected %i and got len %i\n",checkLen,len); - return; - } - checkCheckSum = 0; - for(i = 0; i < len-1; i++) { - checkCheckSum += data[i]; - } - if(checkCheckSum != data[len-1]) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: discarding packet bad expected checksum, expected %i and got checksum %i\n",(int)data[len-1],(int)checkCheckSum); - return; - } - cmd = data[3]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming[ver=%i]: processing command %i (%s) with %i bytes\n",version,cmd,TuyaMCU_GetCommandTypeLabel(cmd),len); - switch(cmd) - { - case TUYA_CMD_STATE: - TuyaMCU_ParseStateMessage(data+6,len-6); - break; - case TUYA_CMD_SET_TIME: - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: received TUYA_CMD_SET_TIME, so sending back time"); - TuyaMCU_Send_SetTime(TuyaMCU_Get_NTP_Time()); - break; - // 55 AA 00 01 00 ${"p":"e7dny8zvmiyhqerw","v":"1.0.0"}$ - // tuyaMcu_fakeHex 55AA000100247B2270223A226537646E79387A766D69796871657277222C2276223A22312E302E30227D24 - case TUYA_CMD_QUERY_PRODUCT: - TuyaMCU_ParseQueryProductInformation(data+6,len-6); - break; - // this name seems invalid for Version 0 of TuyaMCU - case TUYA_CMD_QUERY_STATE: - if(version == 0) { - // 0x08 packet for version 0 (not 0x03) of TuyaMCU - TuyaMCU_V0_ParseRealTimeWithRecordStorage(data+6,len-6); - } else { + if(data[0] != 0x55 || data[1] != 0xAA) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: discarding packet with bad ident and len %i\n",len); + return; + } + version = data[2]; + checkLen = data[5] | data[4] >> 8; + checkLen = checkLen + 2 + 1 + 1 + 2 + 1; + if(checkLen != len) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: discarding packet bad expected len, expected %i and got len %i\n",checkLen,len); + return; + } + checkCheckSum = 0; + for(i = 0; i < len-1; i++) { + checkCheckSum += data[i]; + } + if(checkCheckSum != data[len-1]) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: discarding packet bad expected checksum, expected %i and got checksum %i\n",(int)data[len-1],(int)checkCheckSum); + return; + } + cmd = data[3]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming[ver=%i]: processing command %i (%s) with %i bytes\n",version,cmd,TuyaMCU_GetCommandTypeLabel(cmd),len); + switch(cmd) + { + case TUYA_CMD_HEARTBEAT: + heartbeat_valid = true; + heartbeat_counter = 0; + break; + case TUYA_CMD_MCU_CONF: + working_mode_valid = true; + if (checkLen == 0) + { + self_processing_mode = true; + } + else if (checkLen == 2) + { + self_processing_mode = false; + } + break; + case TUYA_CMD_WIFI_STATE: + wifi_state_valid = true; + break; - } - break; - default: - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: unhandled type %i",cmd); - break; - } + case TUYA_CMD_STATE: + TuyaMCU_ParseStateMessage(data+6,len-6); + state_updated = true; + break; + case TUYA_CMD_SET_TIME: + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: received TUYA_CMD_SET_TIME, so sending back time"); + TuyaMCU_Send_SetTime(TuyaMCU_Get_NTP_Time()); + break; + // 55 AA 00 01 00 ${"p":"e7dny8zvmiyhqerw","v":"1.0.0"}$ + // tuyaMcu_fakeHex 55AA000100247B2270223A226537646E79387A766D69796871657277222C2276223A22312E302E30227D24 + case TUYA_CMD_QUERY_PRODUCT: + TuyaMCU_ParseQueryProductInformation(data+6,len-6); + product_information_valid = true; + break; + // this name seems invalid for Version 0 of TuyaMCU + case TUYA_CMD_QUERY_STATE: + if(version == 0) { + // 0x08 packet for version 0 (not 0x03) of TuyaMCU + TuyaMCU_V0_ParseRealTimeWithRecordStorage(data+6,len-6); + } else { + + } + break; + default: + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: unhandled type %i",cmd); + break; + } } -int TuyaMCU_FakePacket(const void *context, const char *cmd, const char *args, int cmdFlags) { - byte packet[256]; - int c = 0; - if(!(*args)) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_FakePacket: requires 1 argument (hex string, like FFAABB00CCDD\n"); - return -1; - } - while(*args) { - byte b; - b = hexbyte(args); - if(sizeof(packet)>c+1) { - packet[c] = b; - c++; - } - args += 2; - } - TuyaMCU_ProcessIncoming(packet,c); - return 1; +int TuyaMCU_FakePacket(const void *context, const char *cmd, const char *args, int cmdFlags) { + byte packet[256]; + int c = 0; + if(!(*args)) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_FakePacket: requires 1 argument (hex string, like FFAABB00CCDD\n"); + return -1; + } + while(*args) { + byte b; + b = hexbyte(args); + + if(sizeof(packet)>c+1) { + packet[c] = b; + c++; + } + args += 2; + } + TuyaMCU_ProcessIncoming(packet,c); + return 1; } void TuyaMCU_RunFrame() { - byte data[128]; - char buffer_for_log[256]; - char buffer2[4]; - int len, i; + byte data[128]; + char buffer_for_log[256]; + char buffer2[4]; + int len, i; - //addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"UART ring buffer state: %i %i\n",g_recvBufIn,g_recvBufOut); + //addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"UART ring buffer state: %i %i\n",g_recvBufIn,g_recvBufOut); while (1) { - len = UART_TryToGetNextTuyaPacket(data,sizeof(data)); - if(len > 0) { - buffer_for_log[0] = 0; - for(i = 0; i < len; i++) { - sprintf(buffer2,"%02X ",data[i]); - strcat_safe(buffer_for_log,buffer2,sizeof(buffer_for_log)); - } - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TUYAMCU received: %s\n", buffer_for_log); - TuyaMCU_ProcessIncoming(data,len); - } else { + len = UART_TryToGetNextTuyaPacket(data,sizeof(data)); + if(len > 0) { + buffer_for_log[0] = 0; + for(i = 0; i < len; i++) { + sprintf(buffer2,"%02X ",data[i]); + strcat_safe(buffer_for_log,buffer2,sizeof(buffer_for_log)); + } + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TUYAMCU received: %s\n", buffer_for_log); + TuyaMCU_ProcessIncoming(data,len); + } else { break; } } @@ -1005,38 +1043,38 @@ void TuyaMCU_RunFrame() { int TuyaMCU_SetBaudRate(const void *context, const char *cmd, const char *args, int cmdFlags) { - Tokenizer_TokenizeString(args); + Tokenizer_TokenizeString(args); - if(Tokenizer_GetArgsCount() < 1) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_SetBaudRate: requires 1 arguments (baudRate)\n"); - return -1; - } + if(Tokenizer_GetArgsCount() < 1) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_SetBaudRate: requires 1 arguments (baudRate)\n"); + return -1; + } - g_baudRate = Tokenizer_GetArgInteger(0); - - return 1; + g_baudRate = Tokenizer_GetArgInteger(0); + + return 1; } void TuyaMCU_Init() { - UART_InitUART(g_baudRate); - UART_InitReceiveRingBuffer(256); - // uartSendHex 55AA0008000007 - CMD_RegisterCommand("tuyaMcu_testSendTime","",TuyaMCU_Send_SetTime_Example, "Sends a example date by TuyaMCU to clock/callendar MCU", NULL); - CMD_RegisterCommand("tuyaMcu_sendCurTime","",TuyaMCU_Send_SetTime_Current, "Sends a current date by TuyaMCU to clock/callendar MCU", NULL); - CMD_RegisterCommand("uartSendHex","",TuyaMCU_Send_Hex, "Sends raw data by TuyaMCU UART, you must write whole packet with checksum yourself", NULL); - CMD_RegisterCommand("tuyaMcu_fakeHex","",TuyaMCU_Fake_Hex, "qq", NULL); - ///CMD_RegisterCommand("tuyaMcu_sendSimple","",TuyaMCU_Send_Simple, "Appends a 0x55 0xAA header to a data, append a checksum at end and send"); - CMD_RegisterCommand("linkTuyaMCUOutputToChannel","",TuyaMCU_LinkTuyaMCUOutputToChannel, "Map value send from TuyaMCU (eg. humidity or temperature) to channel", NULL); - CMD_RegisterCommand("tuyaMcu_setDimmerRange","",TuyaMCU_SetDimmerRange, "Set dimmer range used by TuyaMCU", NULL); - CMD_RegisterCommand("tuyaMcu_sendHeartbeat","",TuyaMCU_SendHeartbeat, "Send heartbeat to TuyaMCU", NULL); - CMD_RegisterCommand("tuyaMcu_sendQueryState","",TuyaMCU_SendQueryState, "Send query state command", NULL); - CMD_RegisterCommand("tuyaMcu_sendProductInformation","",TuyaMCU_SendQueryProductInformation, "Send qqq", NULL); - CMD_RegisterCommand("tuyaMcu_sendState","",TuyaMCU_SendStateCmd, "Send set state command", NULL); - CMD_RegisterCommand("tuyaMcu_sendMCUConf","",TuyaMCU_SendMCUConf, "Send MCU conf command", NULL); - CMD_RegisterCommand("fakeTuyaPacket","",TuyaMCU_FakePacket, "qq", NULL); - CMD_RegisterCommand("tuyaMcu_setBaudRate","",TuyaMCU_SetBaudRate, "Set the serial baud rate used to communicate with the TuyaMCU", NULL); + UART_InitUART(g_baudRate); + UART_InitReceiveRingBuffer(256); + // uartSendHex 55AA0008000007 + CMD_RegisterCommand("tuyaMcu_testSendTime","",TuyaMCU_Send_SetTime_Example, "Sends a example date by TuyaMCU to clock/callendar MCU", NULL); + CMD_RegisterCommand("tuyaMcu_sendCurTime","",TuyaMCU_Send_SetTime_Current, "Sends a current date by TuyaMCU to clock/callendar MCU", NULL); + CMD_RegisterCommand("uartSendHex","",TuyaMCU_Send_Hex, "Sends raw data by TuyaMCU UART, you must write whole packet with checksum yourself", NULL); + CMD_RegisterCommand("tuyaMcu_fakeHex","",TuyaMCU_Fake_Hex, "qq", NULL); + ///CMD_RegisterCommand("tuyaMcu_sendSimple","",TuyaMCU_Send_Simple, "Appends a 0x55 0xAA header to a data, append a checksum at end and send"); + CMD_RegisterCommand("linkTuyaMCUOutputToChannel","",TuyaMCU_LinkTuyaMCUOutputToChannel, "Map value send from TuyaMCU (eg. humidity or temperature) to channel", NULL); + CMD_RegisterCommand("tuyaMcu_setDimmerRange","",TuyaMCU_SetDimmerRange, "Set dimmer range used by TuyaMCU", NULL); + CMD_RegisterCommand("tuyaMcu_sendHeartbeat","",TuyaMCU_SendHeartbeat, "Send heartbeat to TuyaMCU", NULL); + CMD_RegisterCommand("tuyaMcu_sendQueryState","",TuyaMCU_SendQueryState, "Send query state command", NULL); + CMD_RegisterCommand("tuyaMcu_sendProductInformation","",TuyaMCU_SendQueryProductInformation, "Send qqq", NULL); + CMD_RegisterCommand("tuyaMcu_sendState","",TuyaMCU_SendStateCmd, "Send set state command", NULL); + CMD_RegisterCommand("tuyaMcu_sendMCUConf","",TuyaMCU_SendMCUConf, "Send MCU conf command", NULL); + CMD_RegisterCommand("fakeTuyaPacket","",TuyaMCU_FakePacket, "qq", NULL); + CMD_RegisterCommand("tuyaMcu_setBaudRate","",TuyaMCU_SetBaudRate, "Set the serial baud rate used to communicate with the TuyaMCU", NULL); } // Door sensor with TuyaMCU version 0 (not 3), so all replies have x00 and not 0x03 byte // fakeTuyaPacket 55AA0008000C00010101010101030400010223 @@ -1048,7 +1086,7 @@ void TuyaMCU_Init() /// 55AA 00 08 000C 00 02 02 02 02 02 02 01 01 0001 01 23 /// head vr id size FL YY MM DD HH MM SS ID TP SIZE VL CK /// 55AA 00 08 000C 00 01 01 01 01 01 01 03 04 0001 02 23 -// TP = 0x01 bool 1 Value range: 0x00/0x01. -// TP = 0x04 enum 1 Enumeration type, ranging from 0 to 255. +// TP = 0x01 bool 1 Value range: 0x00/0x01. +// TP = 0x04 enum 1 Enumeration type, ranging from 0 to 255. diff --git a/src/httpserver/hass.c b/src/httpserver/hass.c index d1b77d5ea..b655b457c 100644 --- a/src/httpserver/hass.c +++ b/src/httpserver/hass.c @@ -134,7 +134,10 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, char* payload break; case ENTITY_SENSOR: #ifndef OBK_DISABLE_ALL_DRIVERS - sprintf(g_hassBuffer, "%s %s", CFG_GetShortDeviceName(), sensor_mqttNames[index]); + if ((index >= OBK_VOLTAGE) && (index <= OBK_POWER)) + sprintf(g_hassBuffer, "%s %s", CFG_GetShortDeviceName(), sensor_mqttNames[index]); + if ((index >= OBK_CONSUMPTION_TOTAL) && (index <= OBK_CONSUMPTION_STATS)) + sprintf(g_hassBuffer, "%s %s", CFG_GetShortDeviceName(), counter_mqttNames[index - OBK_CONSUMPTION_TOTAL]); #endif break; } @@ -231,10 +234,20 @@ HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type, int index) { //https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes //device_class automatically assigns unit,icon - cJSON_AddStringToObject(info->root, "dev_cla", sensor_mqttNames[index]); //device_class=voltage,current,power + if ((index >= OBK_VOLTAGE) && (index <= OBK_POWER)) + { + cJSON_AddStringToObject(info->root, "dev_cla", sensor_mqttNames[index]); //device_class=voltage,current,power - sprintf(g_hassBuffer, "%s/%s/get", clientId, sensor_mqttNames[index]); - cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); + sprintf(g_hassBuffer, "%s/%s/get", clientId, sensor_mqttNames[index]); + cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); + } + if ((index >= OBK_CONSUMPTION_TOTAL) && (index <= OBK_CONSUMPTION_STATS)) + { + cJSON_AddStringToObject(info->root, "dev_cla", counter_mqttNames[index - OBK_CONSUMPTION_TOTAL]); //device_class=consumption + + sprintf(g_hassBuffer, "%s/%s/get", clientId, counter_mqttNames[index - OBK_CONSUMPTION_TOTAL]); + cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); + } #endif break; diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index 23b2779a5..cad02feca 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -92,8 +92,9 @@ template_t g_templates[] = { { Setup_Device_Enbrighten_WFD4103, "Enbrighten WFD4103 WiFi Switch BK7231T WB2S"} , { Setup_Device_Zemismart_Light_Switch_KS_811_3, "Zemismart Light Switch (Neutral Optional) KS_811_3"} , { Setup_Device_TeslaSmartPlus_TSL_SPL_1, "Tesla Smart Plug. Model: (TSL-SPL-1)"}, - { Setup_Device_Calex_900011_1_WB2S, "Calex Smart Power Plug 900011.1"} - + { Setup_Device_Calex_900011_1_WB2S, "Calex Smart Power Plug 900011.1"}, + { Setup_Device_Immax_NEO_LITE_NAS_WR07W, "Immax NEO Lite. Model: (NAS-WR07W)"} , + { Setup_Device_MOES_TouchSwitch_WS_EU1_RFW_N, "MOES Touch Switch 1gang Model:(WS-EU1-RFW-N)"} }; int g_total_templates = sizeof(g_templates) / sizeof(g_templates[0]); @@ -548,6 +549,34 @@ int http_fn_index(http_request_t* request) { hprintf128(request, "MQTT Stats:CONN: %d PUB: %d RECV: %d ERR: %d ", MQTT_GetConnectEvents(), MQTT_GetPublishEventCounter(), MQTT_GetReceivedEventCounter(), MQTT_GetPublishErrorCounter()); + /* Format current PINS input state for all unused pins */ + if(CFG_HasFlag(OBK_FLAG_HTTP_PINMONITOR)) + { + for (i=0;i<29;i++) + { + if ((PIN_GetPinRoleForPinIndex(i) == IOR_None) && (i!=10) && (i!=11)) + { + HAL_PIN_Setup_Input(i); + } + } + + hprintf128(request,"
PIN States
"); + for (i=0;i<29;i++) + { + if ((PIN_GetPinRoleForPinIndex(i) != IOR_None) || (i==10) || (i==11)) + { + hprintf128(request,"P%02i: NA ", i); + } else { + hprintf128(request,"P%02i: %i ", i, (int)HAL_PIN_ReadDigitalInput(i)); + } + if (i%10==9) + { + hprintf128(request,"
"); + } + } + hprintf128(request,"
"); + } + // for normal page loads, show the rest of the HTML if (!http_getArg(request->url, "state", tmpA, sizeof(tmpA))) { poststr(request, ""); // end div#state @@ -1280,7 +1309,7 @@ int http_fn_ha_discovery(http_request_t* request) { #ifndef OBK_DISABLE_ALL_DRIVERS if (DRV_IsMeasuringPower()) { - for (i = 0;i < OBK_NUM_MEASUREMENTS;i++) + for (i = 0;i < OBK_NUM_SENSOR_COUNT;i++) { HassDeviceInfo* dev_info = hass_init_light_device_info(ENTITY_SENSOR, i); MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); @@ -1500,24 +1529,32 @@ int http_tasmota_json_power(http_request_t* request) { */ int http_tasmota_json_status_SNS(http_request_t* request) { float power, factor, voltage, current; + float energy, energy_hour; #ifndef OBK_DISABLE_ALL_DRIVERS factor = 0; // TODO voltage = DRV_GetReading(OBK_VOLTAGE); current = DRV_GetReading(OBK_CURRENT); power = DRV_GetReading(OBK_POWER); + energy = DRV_GetReading(OBK_CONSUMPTION_TOTAL); + energy_hour = DRV_GetReading(OBK_CONSUMPTION_LAST_HOUR); + #else factor = 0; voltage = 0; current = 0; power = 0; + energy = 0; + energy_hour = 0; #endif hprintf128(request, "{\"StatusSNS\":{\"ENERGY\":{"); hprintf128(request, "\"Power\": %f,", power); hprintf128(request, "\"ApparentPower\": 0,\"ReactivePower\": 0,\"Factor\":%f,", factor); hprintf128(request, "\"Voltage\":%f,", voltage); - hprintf128(request, "\"Current\":%f}}}", current); + hprintf128(request, "\"Current\":%f,", current); + hprintf128(request, "\"ConsumptionTotal\":%f,", energy); + hprintf128(request, "\"ConsumptionLastHour\":%f}}}", energy_hour); return 0; } @@ -1756,6 +1793,7 @@ const char* g_obk_flagNames[] = { "[MQTT] Broadcast self state on MQTT connect", "[PWM] BK7231 use 600hz instead of 1khz default", "[LED] remember LED driver state (RGBCW, enable, brightness, temperature) after reboot", + "[HTTP] Show actual PIN logic level for unconfigured pins", "error", "error", }; diff --git a/src/new_builtin_devices.c b/src/new_builtin_devices.c index 3fc9ef3ff..0a9e2b9f0 100644 --- a/src/new_builtin_devices.c +++ b/src/new_builtin_devices.c @@ -910,6 +910,9 @@ void Setup_Device_TeslaSmartPlus_TSL_SPL_1() { PIN_SetPinRoleForPinIndex(24, IOR_BL0937_SEL); PIN_SetPinChannelForPinIndex(24, 0); + CFG_SetFlag(2,1); + CFG_SetFlag(10,1); + CFG_Save_SetupTimer(); } @@ -930,3 +933,33 @@ void Setup_Device_Calex_900011_1_WB2S(){ CFG_Save_SetupTimer(); } +void Setup_Device_Immax_NEO_LITE_NAS_WR07W() +{ + CFG_ClearPins(); + + // Button + PIN_SetPinRoleForPinIndex(9, IOR_Button_n); + PIN_SetPinChannelForPinIndex(9, 0); + // Relay + PIN_SetPinRoleForPinIndex(6, IOR_LED_WIFI_n); + PIN_SetPinChannelForPinIndex(6, 0); + // Led + PIN_SetPinRoleForPinIndex(26, IOR_Relay); + PIN_SetPinChannelForPinIndex(26, 0); + + CFG_SetShortStartupCommand("backlog startDriver BL0942"); + CFG_SetFlag(2,1); + CFG_SetFlag(10,1); + + CFG_Save_SetupTimer(); +} + +void Setup_Device_MOES_TouchSwitch_WS_EU1_RFW_N() +{ + CFG_ClearPins(); + CFG_SetShortStartupCommand("backlog startDriver TuyaMCU; setChannelType 1 toggle; linkTuyaMCUOutputToChannel 1 bool 1"); + CFG_SetFlag(2,1); + CFG_SetFlag(10,1); + CFG_Save_SetupTimer(); +} + diff --git a/src/new_pins.h b/src/new_pins.h index 596ff9081..4686511a2 100644 --- a/src/new_pins.h +++ b/src/new_pins.h @@ -119,8 +119,9 @@ typedef struct pinsState_s { #define OBK_FLAG_MQTT_BROADCASTSELFSTATEONCONNECT 10 #define OBK_FLAG_SLOW_PWM 11 #define OBK_FLAG_LED_REMEMBERLASTSTATE 12 +#define OBK_FLAG_HTTP_PINMONITOR 13 -#define OBK_TOTAL_FLAGS 13 +#define OBK_TOTAL_FLAGS 14 #define CGF_MQTT_CLIENT_ID_SIZE 64 @@ -271,5 +272,6 @@ void Setup_Device_Aubess_Mini_Smart_Switch_16A(); void Setup_Device_Zemismart_Light_Switch_KS_811_3(); void Setup_Device_TeslaSmartPlus_TSL_SPL_1(); void Setup_Device_Calex_900011_1_WB2S(); - +void Setup_Device_Immax_NEO_LITE_NAS_WR07W(); +void Setup_Device_MOES_TouchSwitch_WS_EU1_RFW_N(); #endif