diff --git a/src/driver/drv_local.h b/src/driver/drv_local.h index 6b95126e0..122a5acf2 100644 --- a/src/driver/drv_local.h +++ b/src/driver/drv_local.h @@ -67,6 +67,11 @@ void SHT3X_AppendInformationToHTTPIndexPage(http_request_t* request); void SHT3X_OnEverySecond(); void SHT3X_StopDriver(); +void SGP_Init(); +void SGP_AppendInformationToHTTPIndexPage(http_request_t* request); +void SGP_OnEverySecond(); +void SGP_StopDriver(); + void Batt_Init(); void Batt_OnEverySecond(); void Batt_AppendInformationToHTTPIndexPage(http_request_t* request); @@ -93,12 +98,12 @@ typedef struct softI2C_s { void Soft_I2C_SetLow(uint8_t pin); void Soft_I2C_SetHigh(uint8_t pin); -bool Soft_I2C_PreInit(softI2C_t *i2c); -bool Soft_I2C_WriteByte(softI2C_t *i2c, uint8_t value); -bool Soft_I2C_Start(softI2C_t *i2c, uint8_t addr); -void Soft_I2C_Stop(softI2C_t *i2c); -uint8_t Soft_I2C_ReadByte(softI2C_t *i2c, bool nack); -void Soft_I2C_ReadBytes(softI2C_t *i2c, uint8_t* buf, int numOfBytes); +bool Soft_I2C_PreInit(softI2C_t* i2c); +bool Soft_I2C_WriteByte(softI2C_t* i2c, uint8_t value); +bool Soft_I2C_Start(softI2C_t* i2c, uint8_t addr); +void Soft_I2C_Stop(softI2C_t* i2c); +uint8_t Soft_I2C_ReadByte(softI2C_t* i2c, bool nack); +void Soft_I2C_ReadBytes(softI2C_t* i2c, uint8_t* buf, int numOfBytes); // Shared LED driver commandResult_t CMD_LEDDriver_Map(const void* context, const char* cmd, const char* args, int flags); diff --git a/src/driver/drv_main.c b/src/driver/drv_main.c index b994308ca..5b5e7bed1 100644 --- a/src/driver/drv_main.c +++ b/src/driver/drv_main.c @@ -237,6 +237,12 @@ static driver_t g_drivers[] = { //drvdetail:"descr":"Humidity/temperature sensor. See [SHT Sensor tutorial topic here](https://www.elektroda.com/rtvforum/topic3958369.html), also see [this sensor teardown](https://www.elektroda.com/rtvforum/topic3945688.html)", //drvdetail:"requires":""} { "SHT3X", SHT3X_Init, SHT3X_OnEverySecond, SHT3X_AppendInformationToHTTPIndexPage, NULL, SHT3X_StopDriver, NULL, false }, + //drvdetail:{"name":"SGP", + //drvdetail:"title":"TODO", + //drvdetail:"descr":"Air Quality sensor.", + //drvdetail:"requires":""} + { "SGP", SGP_Init, SGP_OnEverySecond, SGP_AppendInformationToHTTPIndexPage, NULL, SGP_StopDriver, NULL, false }, + //drvdetail:{"name":"ShiftRegister", //drvdetail:"title":"TODO", //drvdetail:"descr":"ShiftRegisterShiftRegisterShiftRegisterShiftRegister", @@ -506,7 +512,7 @@ bool DRV_IsMeasuringBattery() { bool DRV_IsSensor() { #ifndef OBK_DISABLE_ALL_DRIVERS - return DRV_IsRunning("SHT3X") || DRV_IsRunning("CHT8305"); + return DRV_IsRunning("SHT3X") || DRV_IsRunning("CHT8305") || DRV_IsRunning("SGP"); #else return false; #endif diff --git a/src/driver/drv_sgp.c b/src/driver/drv_sgp.c new file mode 100644 index 000000000..d34d279ec --- /dev/null +++ b/src/driver/drv_sgp.c @@ -0,0 +1,268 @@ +#include "../new_common.h" +#include "../new_pins.h" +#include "../new_cfg.h" +// Commands register, execution API and cmd tokenizer +#include "../cmnds/cmd_public.h" +#include "../mqtt/new_mqtt.h" +#include "../logging/logging.h" +#include "drv_local.h" +#include "drv_uart.h" +#include "../httpserver/new_http.h" +#include "../hal/hal_pins.h" + +#include "drv_sgp.h" + + +#define SGP_I2C_ADDRESS (0x58 << 1) + +static byte channel_co2 = 0, channel_tvoc = 0, g_sgpcycle = 1, g_sgpcycleref = 10, g_sgpstate = 0; +static float g_co2 = 0.0, g_tvoc = 0.0; +static softI2C_t g_sgpI2C; + + +void SGP_Readmeasure() { +#if WINDOWS + // TODO: values for simulator so I can test SGP + // on my Windows machine + g_co2 = 120; + g_tvoc = 130; +#else + uint8_t buff[6]; + unsigned int th, tl, hh, hl; + + // launch measurement on sensor. + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS); + Soft_I2C_WriteByte(&g_sgpI2C, 0x20); + Soft_I2C_WriteByte(&g_sgpI2C, 0x08); + Soft_I2C_Stop(&g_sgpI2C); + + rtos_delay_milliseconds(12); + + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS | 1); + Soft_I2C_ReadBytes(&g_sgpI2C, buff, 6); + Soft_I2C_Stop(&g_sgpI2C); + + th = buff[0]; + tl = buff[1]; + hh = buff[3]; + hl = buff[4]; + + addLogAdv(LOG_DEBUG, LOG_FEATURE_SENSOR, "SGP_Measure: Bits %02X %02X %02X %02X", buff[0], buff[1], buff[3], buff[4]); + + g_co2 = ((th * 256 + tl)); + g_tvoc = ((hh * 256 + hl)); +#endif + + channel_co2 = g_cfg.pins.channels[g_sgpI2C.pin_data]; + channel_tvoc = g_cfg.pins.channels2[g_sgpI2C.pin_data]; + if (g_co2 == 400.00 && g_tvoc == 0.00) + { + addLogAdv(LOG_INFO, LOG_FEATURE_SENSOR, "SGP_Measure: Baseline init in progress"); + g_sgpstate = 0; + } + else { + g_sgpstate = 1; + CHANNEL_Set(channel_co2, (int)(g_co2), 0); + CHANNEL_Set(channel_tvoc, (int)(g_tvoc), 0); + } + addLogAdv(LOG_INFO, LOG_FEATURE_SENSOR, "SGP_Measure: CO2 :%.1f ppm tvoc:%.0f ppb", g_co2, g_tvoc); +} + +// StopDriver SGP +void SGP_StopDriver() { + addLogAdv(LOG_INFO, LOG_FEATURE_SENSOR, "SGP : Stopping Driver and reset sensor"); +} + + +void SGP_GetBaseline() +{ + uint32_t baseline; + uint8_t buff[6]; + // launch measurement on sensor. + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS); + Soft_I2C_WriteByte(&g_sgpI2C, 0x20); + Soft_I2C_WriteByte(&g_sgpI2C, 0x15); + Soft_I2C_Stop(&g_sgpI2C); + + rtos_delay_milliseconds(10); + + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS | 1); + Soft_I2C_ReadBytes(&g_sgpI2C, buff, 6); + Soft_I2C_Stop(&g_sgpI2C); + + addLogAdv(LOG_INFO, LOG_FEATURE_SENSOR, "SGP : baseline : %02X %02X %02X %02X", buff[0], buff[1], buff[3], buff[4]); +} +commandResult_t SGP_GetBaselinecmd(const void* context, const char* cmd, const char* args, int cmdFlags) +{ + SGP_GetBaseline(); + return CMD_RES_OK; +} + +void SGP_GetVersion() +{ + uint32_t baseline; + uint8_t buff[3]; + uint16_t feature_set_version; + uint8_t product_type; + + // launch measurement on sensor. + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS); + Soft_I2C_WriteByte(&g_sgpI2C, 0x20); + Soft_I2C_WriteByte(&g_sgpI2C, 0x2f); + Soft_I2C_Stop(&g_sgpI2C); + + rtos_delay_milliseconds(10); + + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS | 1); + Soft_I2C_ReadBytes(&g_sgpI2C, buff, 3); + Soft_I2C_Stop(&g_sgpI2C); + feature_set_version = ((buff[1] * 256) + buff[0]); + product_type = (uint8_t)((feature_set_version & 0xF000) >> 12); + feature_set_version = feature_set_version & 0x00FF; + + addLogAdv(LOG_INFO, LOG_FEATURE_SENSOR, "SGP : Version : %i %i ", feature_set_version, product_type); +} +commandResult_t SGP_GetVersioncmd(const void* context, const char* cmd, const char* args, int cmdFlags) +{ + SGP_GetVersion(); + return CMD_RES_OK; +} + +void SGP_SoftReset() +{ + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS); + Soft_I2C_WriteByte(&g_sgpI2C, 0x00); //Clear status + Soft_I2C_WriteByte(&g_sgpI2C, 0x06); //clear status + Soft_I2C_Stop(&g_sgpI2C); + addLogAdv(LOG_INFO, LOG_FEATURE_SENSOR, "SGP : SOFT RESET"); +} +commandResult_t SGP_SoftResetcmd(const void* context, const char* cmd, const char* args, int cmdFlags) +{ + SGP_SoftReset(); + return CMD_RES_OK; +} + +void SGP_INIT_BASELINE() +{ + Soft_I2C_Start(&g_sgpI2C, SGP_I2C_ADDRESS); + Soft_I2C_WriteByte(&g_sgpI2C, 0x20); + Soft_I2C_WriteByte(&g_sgpI2C, 0x03); + Soft_I2C_Stop(&g_sgpI2C); + addLogAdv(LOG_INFO, LOG_FEATURE_SENSOR, "SGP : Launch INIT Baseline"); +} + + +// Read Baseline +static void SGP_Read_IAQ(float* co2, float* tvoc) +{ +} + +static uint8_t SGP_CalcCrc(uint8_t* data) +{ + uint8_t bit; // bit mask + uint8_t crc = 0xFF; // calculated checksum + + // calculates 8-Bit checksum with given polynomial + crc ^= (data[0]); + for (bit = 8; bit > 0; --bit) + { + if ((crc & 0x80)) + { + crc = (crc << 1) ^ 0x131; + } + else + { + crc = (crc << 1); + } + } + + crc ^= (data[1]); + for (bit = 8; bit > 0; --bit) + { + if ((crc & 0x80)) + { + crc = (crc << 1) ^ 0x131; + } + else + { + crc = (crc << 1); + } + } + + return crc; +} +commandResult_t SGP_cycle(const void* context, const char* cmd, const char* args, int cmdFlags) { + + Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES | TOKENIZER_DONT_EXPAND); + if (Tokenizer_GetArgsCount() < 1) { + ADDLOG_INFO(LOG_FEATURE_CMD, "SHT Cycle : Need integer args for seconds cycle"); + return CMD_RES_NOT_ENOUGH_ARGUMENTS; + } + g_sgpcycleref = Tokenizer_GetArgFloat(0); + + ADDLOG_INFO(LOG_FEATURE_CMD, "SGP Cycle : Measurement will run every %i seconds", g_sgpcycleref); + + return CMD_RES_OK; +} +// startDriver SGP +void SGP_Init() { + + + g_sgpI2C.pin_clk = 9; + g_sgpI2C.pin_data = 14; + + g_sgpI2C.pin_clk = PIN_FindPinIndexForRole(IOR_SGP_CLK, g_sgpI2C.pin_clk); + g_sgpI2C.pin_data = PIN_FindPinIndexForRole(IOR_SGP_DAT, g_sgpI2C.pin_data); + + Soft_I2C_PreInit(&g_sgpI2C); + + //init the baseline + SGP_INIT_BASELINE(); + + rtos_delay_milliseconds(10); + + //cmddetail:{"name":"SGP_cycle","args":"[int]", + //cmddetail:"descr":"change cycle of measurement by default every 10 seconds 0 to deactivate", + //cmddetail:"fn":"SGP_cycle","file":"drv/drv_sgp.c","requires":"", + //cmddetail:"examples":"SGP_Cycle 60"} + CMD_RegisterCommand("SGP_cycle", SGP_cycle, NULL); + //cmddetail:{"name":"SGP_GetVersion","args":"", + //cmddetail:"descr":"SGP : get version", + //cmddetail:"fn":"SGP_GetVersion","file":"drv/drv_sgp.c","requires":"", + //cmddetail:"examples":"SGP_GetVersion"} + CMD_RegisterCommand("SGP_GetVersion", SGP_GetVersioncmd, NULL); + //cmddetail:{"name":"SGP_GetBaseline","args":"", + //cmddetail:"descr":"SGP Get baseline", + //cmddetail:"fn":"SGP_GetBaseline","file":"drv/drv_sgp.c","requires":"", + //cmddetail:"examples":"SGP_GetBaseline"} + CMD_RegisterCommand("SGP_GetBaseline", SGP_GetBaselinecmd, NULL); + //cmddetail:{"name":"SGP_SoftReset","args":"", + //cmddetail:"descr":"SGP i2C soft reset", + //cmddetail:"fn":"SGP_SoftReset","file":"drv/drv_sgp.c","requires":"", + //cmddetail:"examples":"SGP_SoftReset"} + CMD_RegisterCommand("SGP_SoftReset", SGP_SoftResetcmd, NULL); +} +void SGP_OnEverySecond() +{ + + if (g_sgpcycle == 1 || g_sgpstate == 0) { + SGP_Readmeasure(); + g_sgpcycle = g_sgpcycleref; + } + if (g_sgpcycle > 0) { + --g_sgpcycle; + } + ADDLOG_DEBUG(LOG_FEATURE_DRV, "DRV_SGP : Measurement will run in %i cycle", g_sgpcycle); +} + +void SGP_AppendInformationToHTTPIndexPage(http_request_t* request) +{ + + hprintf255(request, "

SGP CO2=%.1f ppm, TVoc=%.0f ppb

", g_co2, g_tvoc); + if (channel_co2 == channel_tvoc) { + hprintf255(request, "WARNING: You don't have configured target channels for co2 and tvoc results, set the first and second channel index in Pins!"); + } + if (g_sgpstate == 0) { + hprintf255(request, "WARNING: Baseline calculation in progress"); + } +} diff --git a/src/driver/drv_sgp.h b/src/driver/drv_sgp.h new file mode 100644 index 000000000..c94d2d428 --- /dev/null +++ b/src/driver/drv_sgp.h @@ -0,0 +1,56 @@ +#define SGT_DELAY 4 +#define SGT_INIT_DELAY 30 + +#define SGP30_PRODUCT_TYPE 0 + +/* command and constants for reading the serial ID */ +#define SGP30_CMD_GET_SERIAL_ID 0x3682 +#define SGP30_CMD_GET_SERIAL_ID_DURATION_US 500 +#define SGP30_CMD_GET_SERIAL_ID_WORDS 3 + +/* command and constants for reading the featureset version */ +#define SGP30_CMD_GET_FEATURESET 0x202f +#define SGP30_CMD_GET_FEATURESET_DURATION_US 10000 +#define SGP30_CMD_GET_FEATURESET_WORDS 1 + +/* command and constants for on-chip self-test */ +#define SGP30_CMD_MEASURE_TEST 0x2032 +#define SGP30_CMD_MEASURE_TEST_DURATION_US 220000 +#define SGP30_CMD_MEASURE_TEST_WORDS 1 +#define SGP30_CMD_MEASURE_TEST_OK 0xd400 + +/* command and constants for IAQ init */ +#define SGP30_CMD_IAQ_INIT 0x2003 +#define SGP30_CMD_IAQ_INIT_DURATION_US 10000 + +/* command and constants for IAQ measure */ +#define SGP30_CMD_IAQ_MEASURE 0x2008 +#define SGP30_CMD_IAQ_MEASURE_DURATION_US 12000 +#define SGP30_CMD_IAQ_MEASURE_WORDS 2 + +/* command and constants for getting IAQ baseline */ +#define SGP30_CMD_GET_IAQ_BASELINE 0x2015 +#define SGP30_CMD_GET_IAQ_BASELINE_DURATION_US 10000 +#define SGP30_CMD_GET_IAQ_BASELINE_WORDS 2 + +/* command and constants for setting IAQ baseline */ +#define SGP30_CMD_SET_IAQ_BASELINE 0x201e +#define SGP30_CMD_SET_IAQ_BASELINE_DURATION_US 10000 + +/* command and constants for raw measure */ +#define SGP30_CMD_RAW_MEASURE 0x2050 +#define SGP30_CMD_RAW_MEASURE_DURATION_US 25000 +#define SGP30_CMD_RAW_MEASURE_WORDS 2 + +/* command and constants for setting absolute humidity */ +#define SGP30_CMD_SET_ABSOLUTE_HUMIDITY 0x2061 +#define SGP30_CMD_SET_ABSOLUTE_HUMIDITY_DURATION_US 10000 + +/* command and constants for getting TVOC inceptive baseline */ +#define SGP30_CMD_GET_TVOC_INCEPTIVE_BASELINE 0x20b3 +#define SGP30_CMD_GET_TVOC_INCEPTIVE_BASELINE_DURATION_US 10000 +#define SGP30_CMD_GET_TVOC_INCEPTIVE_BASELINE_WORDS 1 + +/* command and constants for setting TVOC baseline */ +#define SGP30_CMD_SET_TVOC_BASELINE 0x2077 +#define SGP30_CMD_SET_TVOC_BASELINE_DURATION_US 10000 diff --git a/src/driver/drv_tuyaMCU.c b/src/driver/drv_tuyaMCU.c index aefc56f62..d42c626a8 100644 --- a/src/driver/drv_tuyaMCU.c +++ b/src/driver/drv_tuyaMCU.c @@ -19,6 +19,7 @@ https://developer.tuya.com/en/docs/iot/tuyacloudlowpoweruniversalserialaccesspro #include "../logging/logging.h" #include "../hal/hal_wifi.h" #include "../mqtt/new_mqtt.h" +#include "drv_public.h" #include "drv_tuyaMCU.h" #include "drv_uart.h" #include "drv_public.h" @@ -68,84 +69,84 @@ void TuyaMCU_RunFrame(); #define DP_TYPE_RAW_TAC2121C_YESTERDAY 202 #define DP_TYPE_RAW_TAC2121C_LASTMONTH 203 -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"; +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"; } -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"; +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"; if (t == TUYA_CMD_WEATHERDATA) return "WeatherData"; - if (t == TUYA_CMD_NETWORK_STATUS) - return "NetworkStatus"; - if (t == TUYA_CMD_SET_RSSI) - return "SetRSSI"; - return "Unknown"; + if (t == TUYA_CMD_NETWORK_STATUS) + return "NetworkStatus"; + if (t == TUYA_CMD_SET_RSSI) + return "SetRSSI"; + 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; +tuyaMCUMapping_t* g_tuyaMappings = 0; /** * Dimmer range @@ -153,7 +154,7 @@ tuyaMCUMapping_t *g_tuyaMappings = 0; * Map OpenBK7231T_App's dimmer range of 0..100 to the dimmer range used by TuyMCU. * Use tuyaMCU_setDimmerrange command to set range used by TuyaMCU. */ -// minimum dimmer value as reported by TuyaMCU dimmer + // minimum dimmer value as reported by TuyaMCU dimmer int g_dimmerRangeMin = 0; // maximum dimmer value as reported by TuyaMCU dimmer int g_dimmerRangeMax = 100; @@ -181,45 +182,45 @@ static int g_sendQueryStatePackets = 0; // See: https://imgur.com/a/mEfhfiA static byte g_defaultTuyaMCUWiFiState = 0x00; -tuyaMCUMapping_t *TuyaMCU_FindDefForID(int fnId) { - tuyaMCUMapping_t *cur; +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; + 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* TuyaMCU_FindDefForChannel(int channel) { + 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; } @@ -227,159 +228,161 @@ void TuyaMCU_MapIDToChannel(int fnId, int dpType, int channel) { // 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 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]; - 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)) { - snprintf(buffer2, sizeof(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)) { + snprintf(buffer2, sizeof(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; } // append header, len, everything, checksum -void TuyaMCU_SendCommandWithData(byte cmdType, byte *data, int payload_len) { - int i; +void TuyaMCU_SendCommandWithData(byte cmdType, byte* data, int payload_len) { + 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) { - uint16_t payload_len = 4; - uint8_t payload_buffer[8]; - payload_buffer[0] = id; - payload_buffer[1] = type; - switch (type) { - case DP_TYPE_BOOL: - case DP_TYPE_ENUM: - payload_len += 1; - payload_buffer[2] = 0x00; - payload_buffer[3] = 0x01; - payload_buffer[4] = value[0]; - break; - case DP_TYPE_VALUE: - payload_len += 4; - payload_buffer[2] = 0x00; - payload_buffer[3] = 0x04; - payload_buffer[4] = value[3]; - payload_buffer[5] = value[2]; - payload_buffer[6] = value[1]; - payload_buffer[7] = value[0]; - break; + uint16_t payload_len = 4; + uint8_t payload_buffer[8]; + payload_buffer[0] = id; + payload_buffer[1] = type; + switch (type) { + case DP_TYPE_BOOL: + case DP_TYPE_ENUM: + payload_len += 1; + payload_buffer[2] = 0x00; + payload_buffer[3] = 0x01; + payload_buffer[4] = value[0]; + break; + case DP_TYPE_VALUE: + payload_len += 4; + payload_buffer[2] = 0x00; + payload_buffer[3] = 0x04; + payload_buffer[4] = value[3]; + payload_buffer[5] = value[2]; + payload_buffer[6] = value[1]; + payload_buffer[7] = value[0]; + break; - } + } - TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); + TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); } void TuyaMCU_SendBool(uint8_t id, bool value) { - TuyaMCU_SendState(id, DP_TYPE_BOOL, (uint8_t*)&value); + TuyaMCU_SendState(id, DP_TYPE_BOOL, (uint8_t*)&value); } void TuyaMCU_SendValue(uint8_t id, uint32_t value) { - TuyaMCU_SendState(id, DP_TYPE_VALUE, (uint8_t*)(&value)); + TuyaMCU_SendState(id, DP_TYPE_VALUE, (uint8_t*)(&value)); } void TuyaMCU_SendEnum(uint8_t id, uint32_t value) { - TuyaMCU_SendState(id, DP_TYPE_ENUM, (uint8_t*)(&value)); + TuyaMCU_SendState(id, DP_TYPE_ENUM, (uint8_t*)(&value)); } -static uint16_t convertHexStringtoBytes (uint8_t * dest, char src[], uint16_t src_len){ - char hexbyte[3]; - uint16_t i; +static uint16_t convertHexStringtoBytes(uint8_t* dest, char src[], uint16_t src_len) { + char hexbyte[3]; + uint16_t i; - if (NULL == dest || NULL == src || 0 == src_len){ - return 0; - } + if (NULL == dest || NULL == src || 0 == src_len) { + return 0; + } - hexbyte[2] = 0; + hexbyte[2] = 0; - for (i = 0; i < src_len; i++) { - hexbyte[0] = src[2*i]; - hexbyte[1] = src[2*i+1]; - dest[i] = strtol(hexbyte, NULL, 16); - } + for (i = 0; i < src_len; i++) { + hexbyte[0] = src[2 * i]; + hexbyte[1] = src[2 * i + 1]; + dest[i] = strtol(hexbyte, NULL, 16); + } - return i; + return i; } void TuyaMCU_SendHexString(uint8_t id, char data[]) { @@ -387,17 +390,17 @@ void TuyaMCU_SendHexString(uint8_t id, char data[]) { #else - uint16_t len = strlen(data)/2; - uint16_t payload_len = 4 + len; - uint8_t payload_buffer[payload_len]; - payload_buffer[0] = id; - payload_buffer[1] = DP_TYPE_STRING; - payload_buffer[2] = len >> 8; - payload_buffer[3] = len & 0xFF; + uint16_t len = strlen(data) / 2; + uint16_t payload_len = 4 + len; + uint8_t payload_buffer[payload_len]; + payload_buffer[0] = id; + payload_buffer[1] = DP_TYPE_STRING; + payload_buffer[2] = len >> 8; + payload_buffer[3] = len & 0xFF; - convertHexStringtoBytes(&payload_buffer[4], data, len); + convertHexStringtoBytes(&payload_buffer[4], data, len); - TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); + TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); #endif } @@ -405,19 +408,19 @@ void TuyaMCU_SendString(uint8_t id, char data[]) { #ifdef WIN32 #else - uint16_t len = strlen(data); - uint16_t payload_len = 4 + len; - uint8_t payload_buffer[payload_len]; - payload_buffer[0] = id; - payload_buffer[1] = DP_TYPE_STRING; - payload_buffer[2] = len >> 8; - payload_buffer[3] = len & 0xFF; + uint16_t len = strlen(data); + uint16_t payload_len = 4 + len; + uint8_t payload_buffer[payload_len]; + payload_buffer[0] = id; + payload_buffer[1] = DP_TYPE_STRING; + payload_buffer[2] = len >> 8; + payload_buffer[3] = len & 0xFF; - for (uint16_t i = 0; i < len; i++) { - payload_buffer[4+i] = data[i]; - } + for (uint16_t i = 0; i < len; i++) { + payload_buffer[4 + i] = data[i]; + } - TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); + TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); #endif } @@ -425,33 +428,34 @@ void TuyaMCU_SendRaw(uint8_t id, char data[]) { #ifdef WIN32 #else - char* beginPos = strchr(data, 'x'); - if(!beginPos) { - beginPos = strchr(data, 'X'); - } - if(!beginPos) { - beginPos = data; - } else { - beginPos += 1; - } - uint16_t strSize = strlen(beginPos); - uint16_t len = strSize/2; - uint16_t payload_len = 4 + len; - uint8_t payload_buffer[payload_len]; - payload_buffer[0] = id; - payload_buffer[1] = DP_TYPE_RAW; - payload_buffer[2] = len >> 8; - payload_buffer[3] = len & 0xFF; + char* beginPos = strchr(data, 'x'); + if (!beginPos) { + beginPos = strchr(data, 'X'); + } + if (!beginPos) { + beginPos = data; + } + else { + beginPos += 1; + } + uint16_t strSize = strlen(beginPos); + uint16_t len = strSize / 2; + uint16_t payload_len = 4 + len; + uint8_t payload_buffer[payload_len]; + payload_buffer[0] = id; + payload_buffer[1] = DP_TYPE_RAW; + payload_buffer[2] = len >> 8; + payload_buffer[3] = len & 0xFF; - convertHexStringtoBytes(&payload_buffer[4], beginPos, len); + convertHexStringtoBytes(&payload_buffer[4], beginPos, len); - TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); + TuyaMCU_SendCommandWithData(TUYA_CMD_SET_DP, payload_buffer, payload_len); #endif } /* For setting the Wifi Signal Strength. I tested by using the following. -Take the RSSI for the front web interface (eg -54), calculate the 2's complement (0xCA), +Take the RSSI for the front web interface (eg -54), calculate the 2's complement (0xCA), and manually calculate the checksum and it works. "uartSendHex 55AA 00 24 0001 CA EE" */ @@ -464,13 +468,13 @@ void TuyaMCU_Send_RSSI(int rssi) { } // See this post to find about about arguments of WiFi state // https://www.elektroda.com/rtvforum/viewtopic.php?p=20483899#20483899 -commandResult_t Cmd_TuyaMCU_Set_DefaultWiFiState(const void *context, const char *cmd, const char *args, int cmdFlags) { - +commandResult_t Cmd_TuyaMCU_Set_DefaultWiFiState(const void* context, const char* cmd, const char* args, int cmdFlags) { + g_defaultTuyaMCUWiFiState = atoi(args); - + return CMD_RES_OK; } -commandResult_t Cmd_TuyaMCU_Send_RSSI(const void *context, const char *cmd, const char *args, int cmdFlags) { +commandResult_t Cmd_TuyaMCU_Send_RSSI(const void* context, const char* cmd, const char* args, int cmdFlags) { int toSend; Tokenizer_TokenizeString(args, 0); @@ -484,8 +488,8 @@ commandResult_t Cmd_TuyaMCU_Send_RSSI(const void *context, const char *cmd, cons TuyaMCU_Send_RSSI(toSend); return CMD_RES_OK; } -void TuyaMCU_Send_SetTime(struct tm *pTime) { - byte payload_buffer[8]; +void TuyaMCU_Send_SetTime(struct tm* pTime) { + byte payload_buffer[8]; if (pTime == 0) { memset(payload_buffer, 0, sizeof(payload_buffer)); @@ -515,25 +519,25 @@ void TuyaMCU_Send_SetTime(struct tm *pTime) { 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() { - struct tm * ptm; +struct tm* TuyaMCU_Get_NTP_Time() { + struct tm* ptm; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"MCU time to set: %i\n", g_ntpTime); - ptm = gmtime((time_t*)&g_ntpTime); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "MCU time to set: %i\n", g_ntpTime); + ptm = gmtime((time_t*)&g_ntpTime); if (ptm != 0) { 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; } -void TuyaMCU_Send_RawBuffer(byte *data, int len) { - int i; +void TuyaMCU_Send_RawBuffer(byte* data, int len) { + 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: @@ -543,27 +547,27 @@ void TuyaMCU_Send_RawBuffer(byte *data, int len) { // uartSendHex 55AA000200010406 /*Info:MAIN:Time 143, free 88864, MQTT 1, bWifi 1, secondsWithNoPing -1, socks 2/38 -Info:TuyaMCU:TUYAMCU received: 55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25 +Info:TuyaMCU:TUYAMCU received: 55 AA 00 08 00 0C 00 02 02 02 02 02 02 01 04 00 01 00 25 Info:TuyaMCU:TuyaMCU_ProcessIncoming: processing V0 command 8 with 19 bytes Info:TuyaMCU:TuyaMCU_V0_ParseRealTimeWithRecordStorage: processing dpId 1, dataType 4-DP_TYPE_ENUM and 1 data bytes -Info:TuyaMCU:TuyaMCU_V0_ParseRealTimeWithRecordStorage: raw data 1 byte: +Info:TuyaMCU:TuyaMCU_V0_ParseRealTimeWithRecordStorage: raw data 1 byte: Info:GEN:No change in channel 1 (still set to 0) - ignoring */ -commandResult_t TuyaMCU_LinkTuyaMCUOutputToChannel(const void *context, const char *cmd, const char *args, int cmdFlags) { - int dpId; - const char *dpTypeString; - int dpType; - int channelID; +commandResult_t TuyaMCU_LinkTuyaMCUOutputToChannel(const void* context, const char* cmd, const char* args, int cmdFlags) { + int dpId; + const char* dpTypeString; + int dpType; + int channelID; int argsCount; - // linkTuyaMCUOutputToChannel dpId varType channelID - // linkTuyaMCUOutputToChannel 1 val 1 - Tokenizer_TokenizeString(args,0); + // linkTuyaMCUOutputToChannel dpId varType channelID + // linkTuyaMCUOutputToChannel 1 val 1 + Tokenizer_TokenizeString(args, 0); argsCount = Tokenizer_GetArgsCount(); // following check must be done after 'Tokenizer_TokenizeString', @@ -572,19 +576,24 @@ commandResult_t TuyaMCU_LinkTuyaMCUOutputToChannel(const void *context, const ch if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 2)) { return CMD_RES_NOT_ENOUGH_ARGUMENTS; } - 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 (!stricmp(dpTypeString, "RAW_DDS238")) { + 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 (!stricmp(dpTypeString, "RAW_DDS238")) { // linkTuyaMCUOutputToChannel 6 RAW_DDS238 dpType = DP_TYPE_RAW_DDS238Packet; } @@ -597,64 +606,66 @@ commandResult_t TuyaMCU_LinkTuyaMCUOutputToChannel(const void *context, const ch } else if (!stricmp(dpTypeString, "RAW_TAC2121C_LastMonth")) { dpType = DP_TYPE_RAW_TAC2121C_LASTMONTH; - } 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 CMD_RES_BAD_ARGUMENT; - } - } + } + 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 CMD_RES_BAD_ARGUMENT; + } + } if (argsCount < 2) { channelID = -999; } else { channelID = Tokenizer_GetArgInteger(2); } - - TuyaMCU_MapIDToChannel(dpId, dpType, channelID); - return CMD_RES_OK; + TuyaMCU_MapIDToChannel(dpId, dpType, channelID); + + return CMD_RES_OK; } -commandResult_t TuyaMCU_Send_SetTime_Current(const void *context, const char *cmd, const char *args, int cmdFlags) { +commandResult_t 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 CMD_RES_OK; + return CMD_RES_OK; } -commandResult_t TuyaMCU_Send_SetTime_Example(const void *context, const char *cmd, const char *args, int cmdFlags) { - struct tm testTime; +commandResult_t TuyaMCU_Send_SetTime_Example(const void* context, const char* cmd, const char* args, int cmdFlags) { + 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 CMD_RES_OK; + TuyaMCU_Send_SetTime(&testTime); + return CMD_RES_OK; } -void TuyaMCU_Send(byte *data, int size) { - int i; - unsigned char check_sum; +void TuyaMCU_Send(byte* data, int size) { + 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); } -commandResult_t TuyaMCU_SetDimmerRange(const void *context, const char *cmd, const char *args, int cmdFlags) { - Tokenizer_TokenizeString(args,0); +commandResult_t TuyaMCU_SetDimmerRange(const void* context, const char* cmd, const char* args, int cmdFlags) { + Tokenizer_TokenizeString(args, 0); // following check must be done after 'Tokenizer_TokenizeString', // so we know arguments count in Tokenizer. 'cmd' argument is // only for warning display @@ -662,36 +673,36 @@ commandResult_t TuyaMCU_SetDimmerRange(const void *context, const char *cmd, con return CMD_RES_NOT_ENOUGH_ARGUMENTS; } - g_dimmerRangeMin = Tokenizer_GetArgInteger(0); - g_dimmerRangeMax = Tokenizer_GetArgInteger(1); + g_dimmerRangeMin = Tokenizer_GetArgInteger(0); + g_dimmerRangeMax = Tokenizer_GetArgInteger(1); - return CMD_RES_OK; + return CMD_RES_OK; } -commandResult_t TuyaMCU_SendHeartbeat(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_HEARTBEAT, NULL, 0); +commandResult_t TuyaMCU_SendHeartbeat(const void* context, const char* cmd, const char* args, int cmdFlags) { + TuyaMCU_SendCommandWithData(TUYA_CMD_HEARTBEAT, NULL, 0); - return CMD_RES_OK; + return CMD_RES_OK; } -commandResult_t TuyaMCU_SendQueryProductInformation(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_PRODUCT, NULL, 0); +commandResult_t TuyaMCU_SendQueryProductInformation(const void* context, const char* cmd, const char* args, int cmdFlags) { + TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_PRODUCT, NULL, 0); - return CMD_RES_OK; + return CMD_RES_OK; } -commandResult_t TuyaMCU_SendQueryState(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_STATE, NULL, 0); +commandResult_t TuyaMCU_SendQueryState(const void* context, const char* cmd, const char* args, int cmdFlags) { + TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_STATE, NULL, 0); - return CMD_RES_OK; + return CMD_RES_OK; } -commandResult_t TuyaMCU_SendStateCmd(const void *context, const char *cmd, const char *args, int cmdFlags) { - int dpId; - int dpType; - int value; +commandResult_t TuyaMCU_SendStateCmd(const void* context, const char* cmd, const char* args, int cmdFlags) { + int dpId; + int dpType; + int value; - Tokenizer_TokenizeString(args,0); + Tokenizer_TokenizeString(args, 0); // following check must be done after 'Tokenizer_TokenizeString', // so we know arguments count in Tokenizer. 'cmd' argument is // only for warning display @@ -699,43 +710,44 @@ commandResult_t TuyaMCU_SendStateCmd(const void *context, const char *cmd, const return CMD_RES_NOT_ENOUGH_ARGUMENTS; } - 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 CMD_RES_OK; + return CMD_RES_OK; } -commandResult_t TuyaMCU_SendMCUConf(const void *context, const char *cmd, const char *args, int cmdFlags) { - TuyaMCU_SendCommandWithData(TUYA_CMD_MCU_CONF, NULL, 0); +commandResult_t TuyaMCU_SendMCUConf(const void* context, const char* cmd, const char* args, int cmdFlags) { + TuyaMCU_SendCommandWithData(TUYA_CMD_MCU_CONF, NULL, 0); - return CMD_RES_OK; + return CMD_RES_OK; } void Tuya_SetWifiState(uint8_t state) { - TuyaMCU_SendCommandWithData(TUYA_CMD_WIFI_STATE, &state, 1); + TuyaMCU_SendCommandWithData(TUYA_CMD_WIFI_STATE, &state, 1); } void TuyaMCU_SendNetworkStatus() { - uint8_t state = TUYA_NETWORK_STATUS_NOT_CONNECTED; - if (Main_IsOpenAccessPointMode() != 0 ) { - state = TUYA_NETWORK_STATUS_AP_MODE; - } else if (Main_HasWiFiConnected() != 0 ){ - state = Main_HasMQTTConnected() != 0? TUYA_NETWORK_STATUS_CONNECTED_TO_CLOUD : TUYA_NETWORK_STATUS_CONNECTED_TO_ROUTER; - } - addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU_SendNetworkStatus: sending status 0x%X to MCU \n", state); - TuyaMCU_SendCommandWithData(0x2B, &state, 1); + uint8_t state = TUYA_NETWORK_STATUS_NOT_CONNECTED; + if (Main_IsOpenAccessPointMode() != 0) { + state = TUYA_NETWORK_STATUS_AP_MODE; + } + else if (Main_HasWiFiConnected() != 0) { + state = Main_HasMQTTConnected() != 0 ? TUYA_NETWORK_STATUS_CONNECTED_TO_CLOUD : TUYA_NETWORK_STATUS_CONNECTED_TO_ROUTER; + } + addLogAdv(LOG_DEBUG, LOG_FEATURE_TUYAMCU, "TuyaMCU_SendNetworkStatus: sending status 0x%X to MCU \n", state); + TuyaMCU_SendCommandWithData(0x2B, &state, 1); } void TuyaMCU_ForcePublishChannelValues() { - tuyaMCUMapping_t *cur; + tuyaMCUMapping_t* cur; cur = g_tuyaMappings; while (cur) { - MQTT_ChannelPublish(cur->channel,0); + MQTT_ChannelPublish(cur->channel, 0); cur = cur->next; } return 0; @@ -752,47 +764,47 @@ void TuyaMCU_ForcePublishChannelValues() { // 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; - case ChType_Dimmer1000: - // map TuyaMCU's dimmer range to OpenBK7231T_App's dimmer range 0..1000 - mappedValue = ((value - g_dimmerRangeMin) * 1000) / (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; + case ChType_Dimmer1000: + // map TuyaMCU's dimmer range to OpenBK7231T_App's dimmer range 0..1000 + mappedValue = ((value - g_dimmerRangeMin) * 1000) / (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); } bool TuyaMCU_IsChannelUsedByTuyaMCU(int channel) { - tuyaMCUMapping_t *mapping; + tuyaMCUMapping_t* mapping; // find mapping mapping = TuyaMCU_FindDefForChannel(channel); @@ -803,80 +815,80 @@ bool TuyaMCU_IsChannelUsedByTuyaMCU(int channel) { return true; } 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; - case ChType_Dimmer1000: - // map OpenBK7231T_App's dimmer range 0..256 to TuyaMCU's dimmer range - mappediVal = (((g_dimmerRangeMax - g_dimmerRangeMin) * iVal) / 1000) + 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; + case ChType_Dimmer1000: + // map OpenBK7231T_App's dimmer range 0..256 to TuyaMCU's dimmer range + mappediVal = (((g_dimmerRangeMax - g_dimmerRangeMin) * iVal) / 1000) + 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; +void TuyaMCU_ParseQueryProductInformation(const byte* data, int len) { + 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); } // See: https://www.elektroda.com/rtvforum/viewtopic.php?p=20345606#20345606 -void TuyaMCU_ParseWeatherData(const byte *data, int len) { +void TuyaMCU_ParseWeatherData(const byte* data, int len) { int ofs; byte bValid; //int checkLen; @@ -884,7 +896,7 @@ void TuyaMCU_ParseWeatherData(const byte *data, int len) { byte stringLen; byte varType; char buffer[64]; - const char *stringData; + const char* stringData; //const char *stringDataValue; ofs = 0; @@ -916,7 +928,7 @@ void TuyaMCU_ParseWeatherData(const byte *data, int len) { else { iValue = 0; } - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TuyaMCU_ParseWeatherData: key %s, val integer %i\n",buffer, iValue); + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TuyaMCU_ParseWeatherData: key %s, val integer %i\n", buffer, iValue); } else { // string @@ -941,11 +953,11 @@ void TuyaMCU_ParseWeatherData(const byte *data, int len) { // 55AA 00 06 0005 10 0100 01 00 1C // Head v0 ID lengh fnId leen tp vl CHKSUM -void TuyaMCU_V0_ParseRealTimeWithRecordStorage(const byte *data, int len, bool bIncludesDate) { - int ofs; - int sectorLen; - int fnId; - int dataType; +void TuyaMCU_V0_ParseRealTimeWithRecordStorage(const byte* data, int len, bool bIncludesDate) { + int ofs; + int sectorLen; + int fnId; + int dataType; if (bIncludesDate) { //data[0]; // bDateValid @@ -962,143 +974,144 @@ void TuyaMCU_V0_ParseRealTimeWithRecordStorage(const byte *data, int len, bool b 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_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; +void TuyaMCU_ParseStateMessage(const byte* data, int len) { + int ofs; + int sectorLen; + int fnId; + int dataType; int day, month, year; //int channelType; int iVal; - 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) { - 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); - } - else if(sectorLen == 4) { - 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) { + 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); + } + else if (sectorLen == 4) { + 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); + } else { - tuyaMCUMapping_t *mapping; + tuyaMCUMapping_t* mapping; mapping = TuyaMCU_FindDefForID(fnId); if (mapping != 0) { switch (mapping->dpType) { - case DP_TYPE_RAW_TAC2121C_YESTERDAY: - { - if (sectorLen != 8) { + case DP_TYPE_RAW_TAC2121C_YESTERDAY: + { + if (sectorLen != 8) { - } - else { - month = data[ofs + 4]; - day = data[ofs + 4 + 1]; - // consumption - iVal = data[ofs + 6 + 4] << 8 | data[ofs + 7 + 4]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TAC2121C_YESTERDAY: day %i, month %i, val %i\n", - day, month, iVal); - - } } - break; - case DP_TYPE_RAW_TAC2121C_LASTMONTH: - { - if (sectorLen != 8) { + else { + month = data[ofs + 4]; + day = data[ofs + 4 + 1]; + // consumption + iVal = data[ofs + 6 + 4] << 8 | data[ofs + 7 + 4]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TAC2121C_YESTERDAY: day %i, month %i, val %i\n", + day, month, iVal); - } - else { - year = data[ofs + 4]; - month = data[ofs + 4 + 1]; - // consumption - iVal = data[ofs + 6 + 4] << 8 | data[ofs + 7 + 4]; - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "DP_TYPE_RAW_TAC2121C_LASTMONTH: month %i, year %i, val %i\n", - month, year, iVal); - - } } - break; - case DP_TYPE_RAW_TAC2121C_VCP: - { - if (sectorLen == 8 || sectorLen == 10) { - // voltage - iVal = data[ofs + 0 + 4] << 8 | data[ofs + 1 + 4]; - CHANNEL_SetAllChannelsByType(ChType_Voltage_div10, iVal); - // current - iVal = data[ofs + 3 + 4] << 8 | data[ofs + 4 + 4]; - CHANNEL_SetAllChannelsByType(ChType_Current_div1000, iVal); - // power - iVal = data[ofs + 6 + 4] << 8 | data[ofs + 7 + 4]; - CHANNEL_SetAllChannelsByType(ChType_Power, iVal); - } - else { + } + break; + case DP_TYPE_RAW_TAC2121C_LASTMONTH: + { + if (sectorLen != 8) { - } } - break; - case DP_TYPE_RAW_DDS238Packet: - { - if (sectorLen != 15) { + else { + year = data[ofs + 4]; + month = data[ofs + 4 + 1]; + // consumption + iVal = data[ofs + 6 + 4] << 8 | data[ofs + 7 + 4]; + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "DP_TYPE_RAW_TAC2121C_LASTMONTH: month %i, year %i, val %i\n", + month, year, iVal); - } else { - // FREQ?? - iVal = data[ofs + 8 + 4] << 8 | data[ofs + 9 + 4]; - //CHANNEL_SetAllChannelsByType(QQQQQQ, iVal); - // 06 46 = 1606 => A x 100? ? - iVal = data[ofs + 11 + 4] << 8 | data[ofs + 12 + 4]; - CHANNEL_SetAllChannelsByType(ChType_Current_div1000, iVal); - // Voltage? - iVal = data[ofs + 13 + 4] << 8 | data[ofs + 14 + 4]; - CHANNEL_SetAllChannelsByType(ChType_Voltage_div10, iVal); - } } - break; + } + break; + case DP_TYPE_RAW_TAC2121C_VCP: + { + if (sectorLen == 8 || sectorLen == 10) { + // voltage + iVal = data[ofs + 0 + 4] << 8 | data[ofs + 1 + 4]; + CHANNEL_SetAllChannelsByType(ChType_Voltage_div10, iVal); + // current + iVal = data[ofs + 3 + 4] << 8 | data[ofs + 4 + 4]; + CHANNEL_SetAllChannelsByType(ChType_Current_div1000, iVal); + // power + iVal = data[ofs + 6 + 4] << 8 | data[ofs + 7 + 4]; + CHANNEL_SetAllChannelsByType(ChType_Power, iVal); + } + else { + + } + } + break; + case DP_TYPE_RAW_DDS238Packet: + { + if (sectorLen != 15) { + + } + else { + // FREQ?? + iVal = data[ofs + 8 + 4] << 8 | data[ofs + 9 + 4]; + //CHANNEL_SetAllChannelsByType(QQQQQQ, iVal); + // 06 46 = 1606 => A x 100? ? + iVal = data[ofs + 11 + 4] << 8 | data[ofs + 12 + 4]; + CHANNEL_SetAllChannelsByType(ChType_Current_div1000, iVal); + // Voltage? + iVal = data[ofs + 13 + 4] << 8 | data[ofs + 14 + 4]; + CHANNEL_SetAllChannelsByType(ChType_Voltage_div10, iVal); + } + } + break; } } } - // 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 @@ -1108,157 +1121,159 @@ void TuyaMCU_ParseStateMessage(const byte *data, int len) { #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; +void TuyaMCU_ProcessIncoming(const byte* data, int len) { + 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_HEARTBEAT: - heartbeat_valid = true; - heartbeat_counter = 0; - break; - case TUYA_CMD_MCU_CONF: - working_mode_valid = true; - int dataCount; - // https://github.com/openshwprojects/OpenBK7231T_App/issues/291 - // header ver TUYA_CMD_MCU_CONF LENGHT Chksum - // Pushing - // 55 AA 01 02 00 03 FF 01 01 06 - // 55 AA 01 02 00 03 FF 01 00 05 - // Rotating down - // 55 AA 01 02 00 05 01 24 02 01 0A 39 - // 55 AA 01 02 00 03 01 09 00 0F - // Rotating up - // 55 AA 01 02 00 05 01 24 01 01 0A 38 - // 55 AA 01 02 00 03 01 09 01 10 - dataCount = data[5]; - if (dataCount == 0) - { - self_processing_mode = true; - } - else if (dataCount == 2) - { - self_processing_mode = false; - } - if(5 + dataCount + 2 != len) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: TUYA_CMD_MCU_CONF had wrong data lenght?"); - } else { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: TUYA_CMD_MCU_CONF, TODO!"); - } - break; - case TUYA_CMD_WIFI_STATE: - wifi_state_valid = true; - break; + 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; + int dataCount; + // https://github.com/openshwprojects/OpenBK7231T_App/issues/291 + // header ver TUYA_CMD_MCU_CONF LENGHT Chksum + // Pushing + // 55 AA 01 02 00 03 FF 01 01 06 + // 55 AA 01 02 00 03 FF 01 00 05 + // Rotating down + // 55 AA 01 02 00 05 01 24 02 01 0A 39 + // 55 AA 01 02 00 03 01 09 00 0F + // Rotating up + // 55 AA 01 02 00 05 01 24 01 01 0A 38 + // 55 AA 01 02 00 03 01 09 01 10 + dataCount = data[5]; + if (dataCount == 0) + { + self_processing_mode = true; + } + else if (dataCount == 2) + { + self_processing_mode = false; + } + if (5 + dataCount + 2 != len) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TuyaMCU_ProcessIncoming: TUYA_CMD_MCU_CONF had wrong data lenght?"); + } + else { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TuyaMCU_ProcessIncoming: TUYA_CMD_MCU_CONF, TODO!"); + } + break; + case TUYA_CMD_WIFI_STATE: + wifi_state_valid = true; + break; - case TUYA_CMD_STATE: - TuyaMCU_ParseStateMessage(data+6,len-6); - state_updated = true; - g_sendQueryStatePackets = 0; - 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"}$ - // uartFakeHex 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 - // This packet includes first a DateTime, then RealTimeDataStorage - TuyaMCU_V0_ParseRealTimeWithRecordStorage(data+6,len-6, true); - } else { - - } - break; - case 0x05: - // This was added for this user: - // https://www.elektroda.com/rtvforum/topic3937723.html - if (version == 0) { - // 0x05 packet for version 0 (not 0x03) of TuyaMCU - // This packet has no datetime stamp - TuyaMCU_V0_ParseRealTimeWithRecordStorage(data + 6, len - 6, false); - } - else { - } - break; - case TUYA_CMD_WEATHERDATA: - TuyaMCU_ParseWeatherData(data + 6, len - 6); - break; + case TUYA_CMD_STATE: + TuyaMCU_ParseStateMessage(data + 6, len - 6); + state_updated = true; + g_sendQueryStatePackets = 0; + 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"}$ + // uartFakeHex 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 + // This packet includes first a DateTime, then RealTimeDataStorage + TuyaMCU_V0_ParseRealTimeWithRecordStorage(data + 6, len - 6, true); + } + else { - case TUYA_CMD_SET_RSSI: - // This is send by TH06, S09 - // Info:TuyaMCU:TUYAMCU received: 55 AA 03 24 00 00 26 - if (version == 3) { - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: received TUYA_CMD_SET_RSSI, so sending back signal strength"); - TuyaMCU_Send_RSSI(HAL_GetWifiStrength()); - } - break; + } + break; + case 0x05: + // This was added for this user: + // https://www.elektroda.com/rtvforum/topic3937723.html + if (version == 0) { + // 0x05 packet for version 0 (not 0x03) of TuyaMCU + // This packet has no datetime stamp + TuyaMCU_V0_ParseRealTimeWithRecordStorage(data + 6, len - 6, false); + } + else { + } + break; + case TUYA_CMD_WEATHERDATA: + TuyaMCU_ParseWeatherData(data + 6, len - 6); + break; - case TUYA_CMD_NETWORK_STATUS: - //This is sent by S09 - //Info:TuyaMCU:TUYAMCU received: 55 AA 03 2B 00 00 2D - // - if (version == 3 ){ - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: (test for S09 calendar/IR device) received TUYA_CMD_NETWORK_STATUS 0x2B "); - TuyaMCU_SendNetworkStatus(); - } - break; - default: - addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_ProcessIncoming: unhandled type %i",cmd); - break; - } - EventHandlers_FireEvent(CMD_EVENT_TUYAMCU_PARSED, cmd); + case TUYA_CMD_SET_RSSI: + // This is send by TH06, S09 + // Info:TuyaMCU:TUYAMCU received: 55 AA 03 24 00 00 26 + if (version == 3) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TuyaMCU_ProcessIncoming: received TUYA_CMD_SET_RSSI, so sending back signal strength"); + TuyaMCU_Send_RSSI(HAL_GetWifiStrength()); + } + break; + + case TUYA_CMD_NETWORK_STATUS: + //This is sent by S09 + //Info:TuyaMCU:TUYAMCU received: 55 AA 03 2B 00 00 2D + // + if (version == 3) { + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TuyaMCU_ProcessIncoming: (test for S09 calendar/IR device) received TUYA_CMD_NETWORK_STATUS 0x2B "); + TuyaMCU_SendNetworkStatus(); + } + break; + default: + addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "TuyaMCU_ProcessIncoming: unhandled type %i", cmd); + break; + } + EventHandlers_FireEvent(CMD_EVENT_TUYAMCU_PARSED, cmd); } -commandResult_t 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 CMD_RES_NOT_ENOUGH_ARGUMENTS; - } - while(*args) { - byte b; - b = hexbyte(args); +commandResult_t 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 CMD_RES_NOT_ENOUGH_ARGUMENTS; + } + while (*args) { + byte b; + b = hexbyte(args); - if(sizeof(packet)>c+1) { - packet[c] = b; - c++; - } - args += 2; - } - TuyaMCU_ProcessIncoming(packet,c); - return CMD_RES_OK; + if (sizeof(packet) > c + 1) { + packet[c] = b; + c++; + } + args += 2; + } + TuyaMCU_ProcessIncoming(packet, c); + return CMD_RES_OK; } void TuyaMCU_RunWiFiUpdateAndPackets() { //addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU,"TuyaMCU_WifiCheck %d ", wifi_state_timer); @@ -1295,99 +1310,102 @@ void TuyaMCU_RunWiFiUpdateAndPackets() { } } 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); // extraDebug log level - addLogAdv(LOG_EXTRADEBUG, LOG_FEATURE_TUYAMCU,"TuyaMCU heartbeat_valid = %i, product_information_valid=%i," + addLogAdv(LOG_EXTRADEBUG, LOG_FEATURE_TUYAMCU, "TuyaMCU heartbeat_valid = %i, product_information_valid=%i," " self_processing_mode = %i, wifi_state_valid = %i, wifi_state_timer=%i\n", - (int)heartbeat_valid,(int)product_information_valid,(int)self_processing_mode, - (int)wifi_state_valid,(int)wifi_state_timer); - - while (1) - { - len = UART_TryToGetNextTuyaPacket(data,sizeof(data)); - if(len > 0) { - buffer_for_log[0] = 0; - for(i = 0; i < len; i++) { - snprintf(buffer2, sizeof(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); + (int)heartbeat_valid, (int)product_information_valid, (int)self_processing_mode, + (int)wifi_state_valid, (int)wifi_state_timer); + + while (1) + { + len = UART_TryToGetNextTuyaPacket(data, sizeof(data)); + if (len > 0) { + buffer_for_log[0] = 0; + for (i = 0; i < len; i++) { + snprintf(buffer2, sizeof(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); #if 1 // redo sprintf without spaces - buffer_for_log[0] = 0; - for(i = 0; i < len; i++) { - snprintf(buffer2, sizeof(buffer2),"%02X",data[i]); - strcat_safe(buffer_for_log,buffer2,sizeof(buffer_for_log)); - } + buffer_for_log[0] = 0; + for (i = 0; i < len; i++) { + snprintf(buffer2, sizeof(buffer2), "%02X", data[i]); + strcat_safe(buffer_for_log, buffer2, sizeof(buffer_for_log)); + } // fire string event, as we already have it sprintfed // This is so we can have event handlers that fire // when an UART string is received... - EventHandlers_FireEvent_String(CMD_EVENT_ON_UART,buffer_for_log); + EventHandlers_FireEvent_String(CMD_EVENT_ON_UART, buffer_for_log); #endif - TuyaMCU_ProcessIncoming(data,len); - } else { - break; - } - } + TuyaMCU_ProcessIncoming(data, len); + } + else { + break; + } + } - /* Command controll */ - if (heartbeat_timer == 0) - { - /* Generate heartbeat to keep communication alove */ - TuyaMCU_SendCommandWithData(TUYA_CMD_HEARTBEAT, NULL, 0); - heartbeat_timer = 3; - heartbeat_counter++; - if (heartbeat_counter>=4) - { - /* unanswerred heartbeats -> lost communication */ - heartbeat_valid = false; - product_information_valid = false; - working_mode_valid = false; - wifi_state_valid = false; - state_updated = false; + /* Command controll */ + if (heartbeat_timer == 0) + { + /* Generate heartbeat to keep communication alove */ + TuyaMCU_SendCommandWithData(TUYA_CMD_HEARTBEAT, NULL, 0); + heartbeat_timer = 3; + heartbeat_counter++; + if (heartbeat_counter >= 4) + { + /* unanswerred heartbeats -> lost communication */ + heartbeat_valid = false; + product_information_valid = false; + working_mode_valid = false; + wifi_state_valid = false; + state_updated = false; g_sendQueryStatePackets = 0; - } - //addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "WFS: %d H%d P%d M%d W%d S%d", wifi_state_timer, - // heartbeat_valid, product_information_valid, working_mode_valid, wifi_state_valid, - // state_updated); - } else { - /* Heartbeat timer - sent every 3 seconds */ - if (heartbeat_timer>0) - { - heartbeat_timer--; - } else { - heartbeat_timer = 0; - } - if (heartbeat_valid == true && DRV_IsRunning("tmSensor")==false) - { - /* Connection Active */ - if (product_information_valid == false) - { + } + //addLogAdv(LOG_INFO, LOG_FEATURE_TUYAMCU, "WFS: %d H%d P%d M%d W%d S%d", wifi_state_timer, + // heartbeat_valid, product_information_valid, working_mode_valid, wifi_state_valid, + // state_updated); + } + else { + /* Heartbeat timer - sent every 3 seconds */ + if (heartbeat_timer > 0) + { + heartbeat_timer--; + } + else { + heartbeat_timer = 0; + } + if (heartbeat_valid == true && DRV_IsRunning("tmSensor") == false) + { + /* Connection Active */ + if (product_information_valid == false) + { addLogAdv(LOG_EXTRADEBUG, LOG_FEATURE_TUYAMCU, "Will send TUYA_CMD_QUERY_PRODUCT.\n"); - /* Request production information */ - TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_PRODUCT, NULL, 0); - } - else if (working_mode_valid == false) - { + /* Request production information */ + TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_PRODUCT, NULL, 0); + } + else if (working_mode_valid == false) + { addLogAdv(LOG_EXTRADEBUG, LOG_FEATURE_TUYAMCU, "Will send TUYA_CMD_MCU_CONF.\n"); - /* Request working mode */ - TuyaMCU_SendCommandWithData(TUYA_CMD_MCU_CONF, NULL, 0); - } - else if ((wifi_state_valid == false) && (self_processing_mode == false)) - { - /* Reset wifi state -> Aquirring network connection */ - Tuya_SetWifiState(g_defaultTuyaMCUWiFiState); + /* Request working mode */ + TuyaMCU_SendCommandWithData(TUYA_CMD_MCU_CONF, NULL, 0); + } + else if ((wifi_state_valid == false) && (self_processing_mode == false)) + { + /* Reset wifi state -> Aquirring network connection */ + Tuya_SetWifiState(g_defaultTuyaMCUWiFiState); addLogAdv(LOG_EXTRADEBUG, LOG_FEATURE_TUYAMCU, "Will send TUYA_CMD_WIFI_STATE.\n"); - TuyaMCU_SendCommandWithData(TUYA_CMD_WIFI_STATE, NULL, 0); - } - else if (state_updated == false) - { + TuyaMCU_SendCommandWithData(TUYA_CMD_WIFI_STATE, NULL, 0); + } + else if (state_updated == false) + { // fix for this device getting stuck? // https://www.elektroda.com/rtvforum/topic3936455.html if (g_sendQueryStatePackets > 1 && (g_sendQueryStatePackets % 2 == 0)) { @@ -1397,21 +1415,21 @@ void TuyaMCU_RunFrame() { /* Request first state of all DP - this should list all existing DP */ addLogAdv(LOG_EXTRADEBUG, LOG_FEATURE_TUYAMCU, "Will send TUYA_CMD_QUERY_STATE (state_updated==false, try %i).\n", g_sendQueryStatePackets); - TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_STATE, NULL, 0); + TuyaMCU_SendCommandWithData(TUYA_CMD_QUERY_STATE, NULL, 0); } g_sendQueryStatePackets++; - } - else - { + } + else + { TuyaMCU_RunWiFiUpdateAndPackets(); - } - } - } + } + } + } } -commandResult_t TuyaMCU_SetBaudRate(const void *context, const char *cmd, const char *args, int cmdFlags) { - Tokenizer_TokenizeString(args,0); +commandResult_t TuyaMCU_SetBaudRate(const void* context, const char* cmd, const char* args, int cmdFlags) { + Tokenizer_TokenizeString(args, 0); // following check must be done after 'Tokenizer_TokenizeString', // so we know arguments count in Tokenizer. 'cmd' argument is // only for warning display @@ -1419,73 +1437,73 @@ commandResult_t TuyaMCU_SetBaudRate(const void *context, const char *cmd, const return CMD_RES_NOT_ENOUGH_ARGUMENTS; } - g_baudRate = Tokenizer_GetArgInteger(0); - - return CMD_RES_OK; + g_baudRate = Tokenizer_GetArgInteger(0); + + return CMD_RES_OK; } void TuyaMCU_Init() { - UART_InitUART(g_baudRate); - UART_InitReceiveRingBuffer(256); - // uartSendHex 55AA0008000007 + UART_InitUART(g_baudRate); + UART_InitReceiveRingBuffer(256); + // uartSendHex 55AA0008000007 //cmddetail:{"name":"tuyaMcu_testSendTime","args":"", //cmddetail:"descr":"Sends a example date by TuyaMCU to clock/callendar MCU", //cmddetail:"fn":"TuyaMCU_Send_SetTime_Example","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_testSendTime", TuyaMCU_Send_SetTime_Example, NULL); + CMD_RegisterCommand("tuyaMcu_testSendTime", TuyaMCU_Send_SetTime_Example, NULL); //cmddetail:{"name":"tuyaMcu_sendCurTime","args":"", //cmddetail:"descr":"Sends a current date by TuyaMCU to clock/callendar MCU. Time is taken from NTP driver, so NTP also should be already running.", //cmddetail:"fn":"TuyaMCU_Send_SetTime_Current","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_sendCurTime", TuyaMCU_Send_SetTime_Current, 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("tuyaMcu_sendCurTime", TuyaMCU_Send_SetTime_Current, NULL); + ///CMD_RegisterCommand("tuyaMcu_sendSimple","",TuyaMCU_Send_Simple, "Appends a 0x55 0xAA header to a data, append a checksum at end and send"); //cmddetail:{"name":"linkTuyaMCUOutputToChannel","args":"[dpId][varType][channelID]", //cmddetail:"descr":"Used to map between TuyaMCU dpIDs and our internal channels. Mapping works both ways. DpIDs are per-device, you can get them by sniffing UART communication. Vartypes can also be sniffed from Tuya. VarTypes can be following: 0-raw, 1-bool, 2-value, 3-string, 4-enum, 5-bitmap", //cmddetail:"fn":"TuyaMCU_LinkTuyaMCUOutputToChannel","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("linkTuyaMCUOutputToChannel", TuyaMCU_LinkTuyaMCUOutputToChannel, NULL); + CMD_RegisterCommand("linkTuyaMCUOutputToChannel", TuyaMCU_LinkTuyaMCUOutputToChannel, NULL); //cmddetail:{"name":"tuyaMcu_setDimmerRange","args":"[Min][Max]", //cmddetail:"descr":"Set dimmer range used by TuyaMCU", //cmddetail:"fn":"TuyaMCU_SetDimmerRange","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_setDimmerRange", TuyaMCU_SetDimmerRange, NULL); + CMD_RegisterCommand("tuyaMcu_setDimmerRange", TuyaMCU_SetDimmerRange, NULL); //cmddetail:{"name":"tuyaMcu_sendHeartbeat","args":"", //cmddetail:"descr":"Send heartbeat to TuyaMCU", //cmddetail:"fn":"TuyaMCU_SendHeartbeat","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_sendHeartbeat", TuyaMCU_SendHeartbeat, NULL); + CMD_RegisterCommand("tuyaMcu_sendHeartbeat", TuyaMCU_SendHeartbeat, NULL); //cmddetail:{"name":"tuyaMcu_sendQueryState","args":"", //cmddetail:"descr":"Send query state command. No arguments needed.", //cmddetail:"fn":"TuyaMCU_SendQueryState","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_sendQueryState", TuyaMCU_SendQueryState, NULL); + CMD_RegisterCommand("tuyaMcu_sendQueryState", TuyaMCU_SendQueryState, NULL); //cmddetail:{"name":"tuyaMcu_sendProductInformation","args":"", //cmddetail:"descr":"Send query packet (0x01). No arguments needed.", //cmddetail:"fn":"TuyaMCU_SendQueryProductInformation","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_sendProductInformation", TuyaMCU_SendQueryProductInformation, NULL); + CMD_RegisterCommand("tuyaMcu_sendProductInformation", TuyaMCU_SendQueryProductInformation, NULL); //cmddetail:{"name":"tuyaMcu_sendState","args":"[dpID][dpType][dpValue]", //cmddetail:"descr":"Manually send set state command. Do not use it. Use mapping, so communication is bidirectional and automatic.", //cmddetail:"fn":"TuyaMCU_SendStateCmd","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_sendState", TuyaMCU_SendStateCmd, NULL); + CMD_RegisterCommand("tuyaMcu_sendState", TuyaMCU_SendStateCmd, NULL); //cmddetail:{"name":"tuyaMcu_sendMCUConf","args":"", //cmddetail:"descr":"Send MCU conf command", //cmddetail:"fn":"TuyaMCU_SendMCUConf","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_sendMCUConf", TuyaMCU_SendMCUConf, NULL); + CMD_RegisterCommand("tuyaMcu_sendMCUConf", TuyaMCU_SendMCUConf, NULL); //cmddetail:{"name":"fakeTuyaPacket","args":"[HexString]", //cmddetail:"descr":"This simulates packet being sent from TuyaMCU to our OBK device.", //cmddetail:"fn":"TuyaMCU_FakePacket","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("fakeTuyaPacket",TuyaMCU_FakePacket, NULL); + CMD_RegisterCommand("fakeTuyaPacket", TuyaMCU_FakePacket, NULL); //cmddetail:{"name":"tuyaMcu_setBaudRate","args":"[BaudValue]", //cmddetail:"descr":"Sets the baud rate used by TuyaMCU UART communication. Default value is 9600. Some other devices require 115200.", //cmddetail:"fn":"TuyaMCU_SetBaudRate","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} - CMD_RegisterCommand("tuyaMcu_setBaudRate",TuyaMCU_SetBaudRate, NULL); + CMD_RegisterCommand("tuyaMcu_setBaudRate", TuyaMCU_SetBaudRate, NULL); //cmddetail:{"name":"tuyaMcu_sendRSSI","args":"", //cmddetail:"descr":"Command sends the specific RSSI value to TuyaMCU (it will send current RSSI if no argument is set)", //cmddetail:"fn":"Cmd_TuyaMCU_Send_RSSI","file":"driver/drv_tuyaMCU.c","requires":"", diff --git a/src/httpserver/hass.c b/src/httpserver/hass.c index e840d6b24..ff8ed46e5 100644 --- a/src/httpserver/hass.c +++ b/src/httpserver/hass.c @@ -58,6 +58,12 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id) { case HUMIDITY_SENSOR: sprintf(uniq_id, "%s_%s_%d", longDeviceName, "humidity", index); break; + case CO2_SENSOR: + sprintf(uniq_id, "%s_%s_%d", longDeviceName, "co2", index); + break; + case TVOC_SENSOR: + sprintf(uniq_id, "%s_%s_%d", longDeviceName, "tvoc", index); + break; case BATTERY_SENSOR: sprintf(uniq_id, "%s_%s_%d", longDeviceName, "battery", index); break; @@ -96,6 +102,8 @@ void hass_populate_device_config_channel(ENTITY_TYPE type, char* uniq_id, HassDe sprintf(info->channel, "switch/%s/config", uniq_id); break; + case CO2_SENSOR: + case TVOC_SENSOR: case POWER_SENSOR: case BATTERY_SENSOR: case BATTERY_VOLTAGE_SENSOR: @@ -186,6 +194,14 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, char* payload isSensor = true; sprintf(g_hassBuffer, "%s Humidity", CFG_GetShortDeviceName()); break; + case CO2_SENSOR: + isSensor = true; + sprintf(g_hassBuffer, "%s CO2", CFG_GetShortDeviceName()); + break; + case TVOC_SENSOR: + isSensor = true; + sprintf(g_hassBuffer, "%s Tvoc", CFG_GetShortDeviceName()); + break; case BATTERY_SENSOR: isSensor = true; sprintf(g_hassBuffer, "%s Battery", CFG_GetShortDeviceName()); @@ -282,10 +298,10 @@ HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type) { cJSON_AddStringToObject(info->root, "clr_temp_cmd_t", g_hassBuffer); //color_temp_command_topic cJSON_AddStringToObject(info->root, "clr_temp_stat_t", "~/led_temperature/get"); //color_temp_state_topic - + sprintf(g_hassBuffer, "%.0f", led_temperature_min); cJSON_AddStringToObject(info->root, "min_mirs", g_hassBuffer); //min_mireds - + sprintf(g_hassBuffer, "%.0f", led_temperature_max); cJSON_AddStringToObject(info->root, "max_mirs", g_hassBuffer); //max_mireds } @@ -381,6 +397,18 @@ HassDeviceInfo* hass_init_sensor_device_info(ENTITY_TYPE type, int channel) { sprintf(g_hassBuffer, "~/%d/get", channel); cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); break; + case CO2_SENSOR: + cJSON_AddStringToObject(info->root, "dev_cla", "carbon_dioxide"); + cJSON_AddStringToObject(info->root, "unit_of_meas", "ppm"); + sprintf(g_hassBuffer, "~/%d/get", channel); + cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); + break; + case TVOC_SENSOR: + cJSON_AddStringToObject(info->root, "dev_cla", "volatile_organic_compounds"); + cJSON_AddStringToObject(info->root, "unit_of_meas", "ppb"); + sprintf(g_hassBuffer, "~/%d/get", channel); + cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); + break; case BATTERY_SENSOR: cJSON_AddStringToObject(info->root, "dev_cla", "battery"); cJSON_AddStringToObject(info->root, "unit_of_meas", "%"); diff --git a/src/httpserver/hass.h b/src/httpserver/hass.h index c5bf079c2..d1d8eb197 100644 --- a/src/httpserver/hass.h +++ b/src/httpserver/hass.h @@ -38,7 +38,12 @@ typedef enum { /// @brief Battery level sensor in perc BATTERY_SENSOR, /// @brief Battery votage sensor in mV - BATTERY_VOLTAGE_SENSOR + BATTERY_VOLTAGE_SENSOR, + + /// @brief CO2 sensor in ppm + CO2_SENSOR, + /// @brief TVOC sensor in ppb + TVOC_SENSOR } ENTITY_TYPE; diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index 872542b07..40606c4ef 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -1665,6 +1665,17 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) { MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); hass_free_device_info(dev_info); + discoveryQueued = true; + } + else if (IS_PIN_AIR_SENSOR_ROLE(g_cfg.pins.roles[i])) { + dev_info = hass_init_sensor_device_info(CO2_SENSOR, PIN_GetPinChannelForPinIndex(i)); + MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); + hass_free_device_info(dev_info); + + dev_info = hass_init_sensor_device_info(TVOC_SENSOR, PIN_GetPinChannel2ForPinIndex(i)); + MQTT_QueuePublish(topic, dev_info->channel, hass_build_discovery_json(dev_info), OBK_PUBLISH_FLAG_RETAIN); + hass_free_device_info(dev_info); + discoveryQueued = true; } } @@ -2109,7 +2120,7 @@ int http_fn_cfg_pins(http_request_t* request) { poststr(request, ""); // Primary linked channel // Some roles do not need any channels - if ((si != IOR_SHT3X_CLK && si != IOR_CHT8305_CLK && si != IOR_Button_ToggleAll && si != IOR_Button_ToggleAll_n + if ((si != IOR_SGP_CLK && si != IOR_SHT3X_CLK && si != IOR_CHT8305_CLK && si != IOR_Button_ToggleAll && si != IOR_Button_ToggleAll_n && si != IOR_BL0937_CF && si != IOR_BL0937_CF1 && si != IOR_BL0937_SEL && si != IOR_LED_WIFI && si != IOR_LED_WIFI_n && si != IOR_LED_WIFI_n && !(si >= IOR_IRRecv && si <= IOR_DHT11) @@ -2120,7 +2131,7 @@ int http_fn_cfg_pins(http_request_t* request) { } // Secondary linked channel // For button, is relay index to toggle on double click - if (si == IOR_Button || si == IOR_Button_n || IS_PIN_DHT_ROLE(si) || IS_PIN_TEMP_HUM_SENSOR_ROLE(si)) + if (si == IOR_Button || si == IOR_Button_n || IS_PIN_DHT_ROLE(si) || IS_PIN_TEMP_HUM_SENSOR_ROLE(si) || IS_PIN_AIR_SENSOR_ROLE(si)) { hprintf255(request, "", i, ch2); } diff --git a/src/httpserver/json_interface.c b/src/httpserver/json_interface.c index 16034b921..7f74c95fe 100644 --- a/src/httpserver/json_interface.c +++ b/src/httpserver/json_interface.c @@ -21,19 +21,19 @@ #include "../driver/drv_local.h" #include "../driver/drv_bl_shared.h" -void JSON_PrintKeyValue_String(void* request, jsonCb_t printer, const char *key, const char *value, bool bComma) { +void JSON_PrintKeyValue_String(void* request, jsonCb_t printer, const char* key, const char* value, bool bComma) { printer(request, "\"%s\":\"%s\"", key, value); if (bComma) { printer(request, ","); } } -void JSON_PrintKeyValue_Int(void* request, jsonCb_t printer, const char *key, int value, bool bComma) { +void JSON_PrintKeyValue_Int(void* request, jsonCb_t printer, const char* key, int value, bool bComma) { printer(request, "\"%s\":%i", key, value); if (bComma) { printer(request, ","); } } -void JSON_PrintKeyValue_Float(void* request, jsonCb_t printer, const char *key, float value, bool bComma) { +void JSON_PrintKeyValue_Float(void* request, jsonCb_t printer, const char* key, float value, bool bComma) { printer(request, "\"%s\":%f", key, value); if (bComma) { printer(request, ","); @@ -117,10 +117,10 @@ static int http_tasmota_json_power(void* request, jsonCb_t printer) { // it looks like they include C and W in color if (LED_IsLedDriverChipRunning() || numPWMs == 5) { - sprintf(buff32, "%i,%i,%i,%i,%i",(int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2], (int)rgbcw[3], (int)rgbcw[4]); + sprintf(buff32, "%i,%i,%i,%i,%i", (int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2], (int)rgbcw[3], (int)rgbcw[4]); } else { - sprintf(buff32,"%i,%i,%i", (int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2]); + sprintf(buff32, "%i,%i,%i", (int)rgbcw[0], (int)rgbcw[1], (int)rgbcw[2]); } JSON_PrintKeyValue_String(request, printer, "Color", buff32, true); sprintf(buff32, "%i,%i,%i", (int)hsv[0], (int)hsv[1], (int)hsv[2]); @@ -260,7 +260,7 @@ static int http_tasmota_json_ENERGY(void* request, jsonCb_t printer) { } */ static int http_tasmota_json_SENSOR(void* request, jsonCb_t printer) { - float temperature, humidity; + float chan_val1, chan_val2; int channel_1, channel_2, g_pin_1 = 0; printer(request, ","); if (DRV_IsRunning("SHT3X")) { @@ -268,15 +268,15 @@ static int http_tasmota_json_SENSOR(void* request, jsonCb_t printer) { channel_1 = g_cfg.pins.channels[g_pin_1]; channel_2 = g_cfg.pins.channels2[g_pin_1]; - temperature = CHANNEL_GetFloat(channel_1) / 10.0f; - humidity = CHANNEL_GetFloat(channel_2); + chan_val1 = CHANNEL_GetFloat(channel_1) / 10.0f; + chan_val2 = CHANNEL_GetFloat(channel_2); // writer header printer(request, "\"SHT3X\":"); // following check will clear NaN values printer(request, "{"); - printer(request, "\"Temperature\": %.1f,", temperature); - printer(request, "\"Humidity\": %.0f", humidity); + printer(request, "\"Temperature\": %.1f,", chan_val1); + printer(request, "\"Humidity\": %.0f", chan_val2); // close ENERGY block printer(request, "},"); } @@ -285,15 +285,32 @@ static int http_tasmota_json_SENSOR(void* request, jsonCb_t printer) { channel_1 = g_cfg.pins.channels[g_pin_1]; channel_2 = g_cfg.pins.channels2[g_pin_1]; - temperature = CHANNEL_GetFloat(channel_1) / 10.0f; - humidity = CHANNEL_GetFloat(channel_2); + chan_val1 = CHANNEL_GetFloat(channel_1) / 10.0f; + chan_val2 = CHANNEL_GetFloat(channel_2); // writer header printer(request, "\"CHT8305\":"); // following check will clear NaN values printer(request, "{"); - printer(request, "\"Temperature\": %.1f,", temperature); - printer(request, "\"Humidity\": %.0f", humidity); + printer(request, "\"Temperature\": %.1f,", chan_val1); + printer(request, "\"Humidity\": %.0f", chan_val2); + // close ENERGY block + printer(request, "},"); + } + if (DRV_IsRunning("SGP")) { + g_pin_1 = PIN_FindPinIndexForRole(IOR_SGP_DAT, g_pin_1); + channel_1 = g_cfg.pins.channels[g_pin_1]; + channel_2 = g_cfg.pins.channels2[g_pin_1]; + + chan_val1 = CHANNEL_GetFloat(channel_1); + chan_val2 = CHANNEL_GetFloat(channel_2); + + // writer header + printer(request, "\"SGP\":"); + // following check will clear NaN values + printer(request, "{"); + printer(request, "\"CO2\": %.0f,", chan_val1); + printer(request, "\"Tvoc\": %.0f", chan_val2); // close ENERGY block printer(request, "},"); } @@ -978,7 +995,7 @@ int JSON_ProcessCommandReply(const char* cmd, const char* arg, void* request, js } else if (!wal_strnicmp(cmd, "SSID1", 5)) { printer(request, "{"); - JSON_PrintKeyValue_String(request,printer,"SSID1", CFG_GetWiFiSSID(),false); + JSON_PrintKeyValue_String(request, printer, "SSID1", CFG_GetWiFiSSID(), false); printer(request, "}"); } else if (!wal_strnicmp(cmd, "LED_Map", 7)) { diff --git a/src/httpserver/new_http.c b/src/httpserver/new_http.c index b9a78305d..e95cc8b37 100644 --- a/src/httpserver/new_http.c +++ b/src/httpserver/new_http.c @@ -448,8 +448,9 @@ const char* htmlPinRoleNames[] = { "TM1637_DIO", "TM1637_CLK", "BL0937SEL_n", - "DoorSnsrWSleep_pd", - "error", + "DoorSnsrWSleep_pd", + "SGP_CLK", + "SGP_DAT", "error", "error", "error", diff --git a/src/new_pins.c b/src/new_pins.c index 168a83ceb..02932d563 100644 --- a/src/new_pins.c +++ b/src/new_pins.c @@ -940,7 +940,7 @@ static void Channel_OnChanged(int ch, int prevValue, int iFlags) { } if ((iFlags & CHANNEL_SET_FLAG_SKIP_MQTT) == 0) { if (bCallCb) { - MQTT_ChannelPublish(ch,0); + MQTT_ChannelPublish(ch, 0); } } // Simple event - it just says that there was a change @@ -1287,7 +1287,7 @@ bool CHANNEL_IsPowerRelayChannel(int ch) { int i; for (i = 0; i < PLATFORM_GPIO_MAX; i++) { if (g_cfg.pins.channels[i] == ch) { - int role = g_cfg.pins.roles[i]; + int role = g_cfg.pins.roles[i]; // NOTE: do not include Battery relay if (role == IOR_Relay || role == IOR_Relay_n) { return true; @@ -1305,7 +1305,7 @@ bool CHANNEL_HasRoleThatShouldBePublished(int ch) { if (role == IOR_Relay || role == IOR_Relay_n || role == IOR_LED || role == IOR_LED_n || role == IOR_ADC || role == IOR_BAT_ADC || role == IOR_BAT_Relay - || role == IOR_CHT8305_DAT || role == IOR_SHT3X_DAT + || role == IOR_CHT8305_DAT || role == IOR_SHT3X_DAT || role == IOR_SGP_DAT || role == IOR_DigitalInput || role == IOR_DigitalInput_n || role == IOR_DoorSensorWithDeepSleep || role == IOR_DoorSensorWithDeepSleep_NoPup || role == IOR_DoorSensorWithDeepSleep_pd @@ -1318,8 +1318,8 @@ bool CHANNEL_HasRoleThatShouldBePublished(int ch) { if (IS_PIN_DHT_ROLE(role)) { return true; } - // CHT8305 and SHT3X uses secondary channel for humidity - if (role == IOR_CHT8305_DAT || role == IOR_SHT3X_DAT) { + // SGP, CHT8305 and SHT3X uses secondary channel for humidity + if (role == IOR_CHT8305_DAT || role == IOR_SHT3X_DAT || role == IOR_SGP_DAT) { return true; } } diff --git a/src/new_pins.h b/src/new_pins.h index 32018a944..a30c70494 100644 --- a/src/new_pins.h +++ b/src/new_pins.h @@ -123,13 +123,13 @@ typedef enum ioRole_e { //iodetail:"file":"new_pins.h", //iodetail:"driver":""} IOR_DigitalInput_NoPup_n, -// energy sensor - //iodetail:{"name":"BL0937_SEL", - //iodetail:"title":"TODO", - //iodetail:"descr":"SEL pin for BL0937 energy measuring devices. Set all BL0937 pins to autostart BL0937 driver. Don't forget to calibrate it later.", - //iodetail:"enum":"IOR_BL0937_SEL", - //iodetail:"file":"new_pins.h", - //iodetail:"driver":""} + // energy sensor + //iodetail:{"name":"BL0937_SEL", + //iodetail:"title":"TODO", + //iodetail:"descr":"SEL pin for BL0937 energy measuring devices. Set all BL0937 pins to autostart BL0937 driver. Don't forget to calibrate it later.", + //iodetail:"enum":"IOR_BL0937_SEL", + //iodetail:"file":"new_pins.h", + //iodetail:"driver":""} IOR_BL0937_SEL, //iodetail:{"name":"BL0937_CF", //iodetail:"title":"TODO", @@ -467,6 +467,20 @@ typedef enum ioRole_e { //iodetail:"file":"new_pins.h", //iodetail:"driver":""} IOR_DoorSensorWithDeepSleep_pd, + //iodetail:{"name":"SGP_CLK", + //iodetail:"title":"TODO", + //iodetail:"descr":"SGP Quality Sensor Clock line. will autostart related driver", + //iodetail:"enum":"IOR_SGP_CLK", + //iodetail:"file":"new_pins.h", + //iodetail:"driver":""} + IOR_SGP_CLK, + //iodetail:{"name":"SGP_DAT", + //iodetail:"title":"TODO", + //iodetail:"descr":"SGP Quality Sensor Data line. will autostart related driver", + //iodetail:"enum":"IOR_SGP_DAT", + //iodetail:"file":"new_pins.h", + //iodetail:"driver":""} + IOR_SGP_DAT, //iodetail:{"name":"Total_Options", //iodetail:"title":"TODO", //iodetail:"descr":"Current total number of available IOR roles", @@ -478,6 +492,7 @@ typedef enum ioRole_e { #define IS_PIN_DHT_ROLE(role) (((role)>=IOR_DHT11) && ((role)<=IOR_DHT22)) #define IS_PIN_TEMP_HUM_SENSOR_ROLE(role) (((role)==IOR_SHT3X_DAT) || ((role)==IOR_CHT8305_DAT)) +#define IS_PIN_AIR_SENSOR_ROLE(role) (((role)==IOR_SGP_DAT)) typedef enum channelType_e { //chandetail:{"name":"Default", diff --git a/src/user_main.c b/src/user_main.c index 67813c525..0f5b8128c 100644 --- a/src/user_main.c +++ b/src/user_main.c @@ -335,7 +335,7 @@ void Main_ScheduleHomeAssistantDiscovery(int seconds) { } void Main_ConnectToWiFiNow() { - const char* wifi_ssid, *wifi_pass; + const char* wifi_ssid, * wifi_pass; g_bOpenAccessPointMode = 0; wifi_ssid = CFG_GetWiFiSSID(); @@ -698,7 +698,7 @@ void QuickTick(void* param) #if (defined WINDOWS) || (defined PLATFORM_BEKEN) SVM_RunThreads(t_diff); #endif - RepeatingEvents_RunUpdate(t_diff*0.001f); + RepeatingEvents_RunUpdate(t_diff * 0.001f); #ifndef OBK_DISABLE_ALL_DRIVERS DRV_RunQuickTick(); #endif @@ -938,8 +938,8 @@ void Main_Init_BeforeDelay_Unsafe(bool bAutoRunScripts) { DRV_StartDriver("BP1658CJ"); #endif } - if (PIN_FindPinIndexForRole(IOR_BL0937_CF, -1) != -1 && PIN_FindPinIndexForRole(IOR_BL0937_CF1, -1) != -1 - && (PIN_FindPinIndexForRole(IOR_BL0937_SEL, -1) != -1|| PIN_FindPinIndexForRole(IOR_BL0937_SEL_n, -1) != -1)) { + if (PIN_FindPinIndexForRole(IOR_BL0937_CF, -1) != -1 && PIN_FindPinIndexForRole(IOR_BL0937_CF1, -1) != -1 + && (PIN_FindPinIndexForRole(IOR_BL0937_SEL, -1) != -1 || PIN_FindPinIndexForRole(IOR_BL0937_SEL_n, -1) != -1)) { #ifndef OBK_DISABLE_ALL_DRIVERS DRV_StartDriver("BL0937"); #endif @@ -966,6 +966,11 @@ void Main_Init_BeforeDelay_Unsafe(bool bAutoRunScripts) { if (PIN_FindPinIndexForRole(IOR_SHT3X_CLK, -1) != -1 && PIN_FindPinIndexForRole(IOR_SHT3X_DAT, -1) != -1) { #ifndef OBK_DISABLE_ALL_DRIVERS DRV_StartDriver("SHT3X"); +#endif + } + if (PIN_FindPinIndexForRole(IOR_SGP_CLK, -1) != -1 && PIN_FindPinIndexForRole(IOR_SGP_DAT, -1) != -1) { +#ifndef OBK_DISABLE_ALL_DRIVERS + DRV_StartDriver("SGP"); #endif } if (PIN_FindPinIndexForRole(IOR_BAT_ADC, -1) != -1) {