diff --git a/src/driver/drv_bltest.c b/src/driver/drv_bltest.c deleted file mode 100644 index 873998e59..000000000 --- a/src/driver/drv_bltest.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "../new_common.h" -#include "drv_local.h" - -//Test driver - -void BLTest_Init() { - BL_Shared_Init(); -} -void BLTest_RunFrame() { - float final_v = 120; - float final_c = 1; - float final_p = 120; - - int r = rand()% 100; - BL_ProcessUpdate(final_v + (r/1000), final_c + (r/10), final_p + r); -} diff --git a/src/driver/drv_local.h b/src/driver/drv_local.h index c76fa514d..8ef302c27 100644 --- a/src/driver/drv_local.h +++ b/src/driver/drv_local.h @@ -10,10 +10,12 @@ void BL0937_RunFrame(); void CSE7766_Init(); void CSE7766_RunFrame(); -#if ENABLE_BL_TEST_DRIVER -void BLTest_Init(); -void BLTest_RunFrame(); -#endif +void Test_Power_Init(); +void Test_Power_RunFrame(); + +void Test_LED_Driver_Init(); +void Test_LED_Driver_RunFrame(); +void Test_LED_Driver_OnChannelChanged(int ch, int value); void DRV_DGR_Init(); void DRV_DGR_RunQuickTick(); @@ -39,11 +41,11 @@ void BP1658CJ_OnChannelChanged(int ch, int value); void BL_Shared_Init(); void BL_ProcessUpdate(float voltage, float current, float power); -void BL09XX_AppendInformationToHTTPIndexPage(http_request_t *request); -bool DRV_IsRunning(const char *name); +void BL09XX_AppendInformationToHTTPIndexPage(http_request_t* request); +bool DRV_IsRunning(const char* name); void TuyaMCU_Sensor_RunFrame(); void TuyaMCU_Sensor_Init(); -int BL09XX_ResetEnergyCounter(const void *context, const char *cmd, const char *args, int cmdFlags); +int BL09XX_ResetEnergyCounter(const void* context, const char* cmd, const char* args, int cmdFlags); diff --git a/src/driver/drv_main.c b/src/driver/drv_main.c index 9d6b9d4ab..7c07db572 100644 --- a/src/driver/drv_main.c +++ b/src/driver/drv_main.c @@ -52,10 +52,10 @@ static driver_t g_drivers[] = { { "BL0942", BL0942_Init, BL0942_RunFrame, BL09XX_AppendInformationToHTTPIndexPage, NULL, NULL, NULL, false }, { "BL0937", BL0937_Init, BL0937_RunFrame, BL09XX_AppendInformationToHTTPIndexPage, NULL, NULL, NULL, false }, { "CSE7766", CSE7766_Init, CSE7766_RunFrame, BL09XX_AppendInformationToHTTPIndexPage, NULL, NULL, NULL, false }, -#if ENABLE_BL_TEST_DRIVER - { "BLTEST", BLTest_Init, BLTest_RunFrame, BL09XX_AppendInformationToHTTPIndexPage, NULL, NULL, NULL, false }, -#endif - + + //Test drivers + { "TESTPOWER", Test_Power_Init, Test_Power_RunFrame, BL09XX_AppendInformationToHTTPIndexPage, NULL, NULL, NULL, false }, + { "TESTLED", Test_LED_Driver_Init, Test_LED_Driver_RunFrame, NULL, NULL, NULL, Test_LED_Driver_OnChannelChanged, false }, #if PLATFORM_BEKEN { "IR", DRV_IR_Init, DRV_IR_RunFrame, NULL, NULL, NULL, NULL, false }, @@ -262,12 +262,7 @@ void DRV_AppendInformationToHTTPIndexPage(http_request_t *request) { bool DRV_IsMeasuringPower(){ #ifndef OBK_DISABLE_ALL_DRIVERS - -#if ENABLE_BL_TEST_DRIVER - return DRV_IsRunning("BLTEST"); -#endif - - return DRV_IsRunning("BL0937") || DRV_IsRunning("BL0942") || DRV_IsRunning("CSE7766"); + return DRV_IsRunning("BL0937") || DRV_IsRunning("BL0942") || DRV_IsRunning("CSE7766") || DRV_IsRunning("TESTPOWER"); #else return false; #endif diff --git a/src/driver/drv_test_drivers.c b/src/driver/drv_test_drivers.c new file mode 100644 index 000000000..d4abbceeb --- /dev/null +++ b/src/driver/drv_test_drivers.c @@ -0,0 +1,23 @@ +#include "../new_common.h" +#include "drv_local.h" + +//Test Power driver +void Test_Power_Init() { + BL_Shared_Init(); +} +void Test_Power_RunFrame() { + float final_v = 120; + float final_c = 1; + float final_p = 120; + + int r = rand() % 100; + BL_ProcessUpdate(final_v + (r / 1000), final_c + (r / 10), final_p + r); +} + +//Test LED driver +void Test_LED_Driver_Init() { +} +void Test_LED_Driver_RunFrame() { +} +void Test_LED_Driver_OnChannelChanged(int ch, int value) { +} \ No newline at end of file diff --git a/src/httpserver/hass.c b/src/httpserver/hass.c index 9ee80cdef..65f8e1024 100644 --- a/src/httpserver/hass.c +++ b/src/httpserver/hass.c @@ -33,6 +33,7 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id) { sprintf(uniq_id, "%s_%s_%d", longDeviceName, "light", index); break; + case ENTITY_LIGHT_PWMCW: case ENTITY_LIGHT_RGB: case ENTITY_LIGHT_RGBCW: sprintf(uniq_id, "%s_%s", longDeviceName, "light"); @@ -66,6 +67,7 @@ void hass_print_unique_id(http_request_t* request, const char* fmt, ENTITY_TYPE void hass_populate_device_config_channel(ENTITY_TYPE type, char* uniq_id, HassDeviceInfo* info) { switch (type) { case ENTITY_LIGHT_PWM: + case ENTITY_LIGHT_PWMCW: case ENTITY_LIGHT_RGB: case ENTITY_LIGHT_RGBCW: sprintf(info->channel, "light/%s/config", uniq_id); @@ -103,9 +105,9 @@ cJSON* hass_build_device_node(cJSON* ids) { /// @brief Initializes HomeAssistant device discovery storage with common values. /// @param type -/// @param index Ignored for RGB, for sensor this corresponds to sensor_mqttNames. -/// @param payload_on -/// @param payload_off +/// @param index This is used to generate generate unique_id and name. It is ignored for RGB. For sensor this corresponds to sensor_mqttNames. +/// @param payload_on The payload that represents enabled state. This is not added for ENTITY_SENSOR. +/// @param payload_off The payload that represents disabled state. This is not added for ENTITY_SENSOR. /// @return HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, char* payload_on, char* payload_off) { HassDeviceInfo* info = os_malloc(sizeof(HassDeviceInfo)); @@ -122,35 +124,39 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, char* payload info->root = cJSON_CreateObject(); cJSON_AddItemToObject(info->root, "dev", info->device); //device + //Build the `name` switch (type) { case ENTITY_LIGHT_PWM: case ENTITY_RELAY: sprintf(g_hassBuffer, "%s %i", CFG_GetShortDeviceName(), index); break; + case ENTITY_LIGHT_PWMCW: case ENTITY_LIGHT_RGB: case ENTITY_LIGHT_RGBCW: - //There can only be one RGB so we can skip including index in the name + //There can only be one RGB so we can skip including index in the name. Do the same + //for 2 PWM case. sprintf(g_hassBuffer, "%s", CFG_GetShortDeviceName()); break; case ENTITY_SENSOR: #ifndef OBK_DISABLE_ALL_DRIVERS - if ((index >= OBK_VOLTAGE) && (index <= OBK_POWER)) - sprintf(g_hassBuffer, "%s %s", CFG_GetShortDeviceName(), sensor_mqttNames[index]); - if ((index >= OBK_CONSUMPTION_TOTAL) && (index <= OBK_CONSUMPTION_STATS)) - sprintf(g_hassBuffer, "%s %s", CFG_GetShortDeviceName(), counter_mqttNames[index - OBK_CONSUMPTION_TOTAL]); + if ((index >= OBK_VOLTAGE) && (index <= OBK_POWER)) + sprintf(g_hassBuffer, "%s %s", CFG_GetShortDeviceName(), sensor_mqttNames[index]); + if ((index >= OBK_CONSUMPTION_TOTAL) && (index <= OBK_CONSUMPTION_STATS)) + sprintf(g_hassBuffer, "%s %s", CFG_GetShortDeviceName(), counter_mqttNames[index - OBK_CONSUMPTION_TOTAL]); #endif break; } cJSON_AddStringToObject(info->root, "name", g_hassBuffer); - cJSON_AddStringToObject(info->root, "~", CFG_GetMQTTClientId()); //base topic - cJSON_AddStringToObject(info->root, "avty_t", "~/connected"); //availability_topic, `online` value is broadcasted - cJSON_AddStringToObject(info->root, "pl_on", payload_on); //payload_on - cJSON_AddStringToObject(info->root, "pl_off", payload_off); //payload_off + if (type != ENTITY_SENSOR) { + cJSON_AddStringToObject(info->root, "pl_on", payload_on); //payload_on + cJSON_AddStringToObject(info->root, "pl_off", payload_off); //payload_off + } cJSON_AddStringToObject(info->root, "uniq_id", info->unique_id); //unique_id + cJSON_AddNumberToObject(info->root, "qos", 1); addLogAdv(LOG_DEBUG, LOG_FEATURE_HASS, "root=%p", info->root); return info; @@ -161,7 +167,6 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, char* payload /// @return HassDeviceInfo* hass_init_relay_device_info(int index) { HassDeviceInfo* info = hass_init_device_info(ENTITY_RELAY, index, "1", "0"); - cJSON_AddNumberToObject(info->root, "qos", 1); sprintf(g_hassBuffer, "~/%i/get", index); cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); //state_topic @@ -173,92 +178,95 @@ HassDeviceInfo* hass_init_relay_device_info(int index) { /// @brief Initializes HomeAssistant light device discovery storage. /// @param type -/// @param index Ignored for RGB, for sensor this corresponds to sensor_mqttNames. /// @return -HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type, int index) { +HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type) { const char* clientId = CFG_GetMQTTClientId(); HassDeviceInfo* info = NULL; + double brightness_scale = 100; + + //We can just use 1 to generate unique_id and name for single PWM. + //The payload_on/payload_off have to match the state_topic/command_topic values. + info = hass_init_device_info(type, 1, "1", "0"); switch (type) { case ENTITY_LIGHT_RGBCW: case ENTITY_LIGHT_RGB: - info = hass_init_device_info(type, index, "1", "0"); - cJSON_AddStringToObject(info->root, "rgb_cmd_tpl", "{{'#%02x%02x%02x0000'|format(red,green,blue)}}"); //rgb_command_template cJSON_AddStringToObject(info->root, "rgb_val_tpl", "{{value[1:3]|int(base=16)}},{{value[3:5]|int(base=16)}},{{value[5:7]|int(base=16)}}"); //rgb_value_template cJSON_AddStringToObject(info->root, "rgb_stat_t", "~/led_basecolor_rgb/get"); //rgb_state_topic sprintf(g_hassBuffer, "cmnd/%s/led_basecolor_rgb", clientId); cJSON_AddStringToObject(info->root, "rgb_cmd_t", g_hassBuffer); //rgb_command_topic - - cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, "~/led_enableAll/get"); //state_topic - sprintf(g_hassBuffer, "cmnd/%s/led_enableAll", clientId); - cJSON_AddStringToObject(info->root, COMMAND_TOPIC_KEY, g_hassBuffer); //command_topic - - cJSON_AddStringToObject(info->root, "bri_stat_t", "~/led_dimmer/get"); //brightness_state_topic - sprintf(g_hassBuffer, "cmnd/%s/led_dimmer", clientId); - cJSON_AddStringToObject(info->root, "bri_cmd_t", g_hassBuffer); //brightness_command_topic - - cJSON_AddNumberToObject(info->root, "bri_scl", 100); //brightness_scale - - if (type == ENTITY_LIGHT_RGBCW) { - sprintf(g_hassBuffer, "cmnd/%s/led_temperature", clientId); - 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 - } - break; case ENTITY_LIGHT_PWM: - info = hass_init_device_info(type, index, "99", "0"); - cJSON_AddStringToObject(info->root, "on_cmd_type", "brightness"); //on_command_type - cJSON_AddNumberToObject(info->root, "bri_scl", 99); //brightness_scale - cJSON_AddBoolToObject(info->root, "opt", cJSON_True); //optimistic - cJSON_AddNumberToObject(info->root, "qos", 1); - - cJSON_AddStringToObject(info->root, "bri_stat_t", "~/led_dimmer/get"); //brightness_state_topic - sprintf(g_hassBuffer, "cmnd/%s/led_dimmer", clientId); - cJSON_AddStringToObject(info->root, "bri_cmd_t", g_hassBuffer); //brightness_command_topic - - sprintf(g_hassBuffer, "~/%i/get", index); - cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); //state_topic - sprintf(g_hassBuffer, "~/%i/set", index); - cJSON_AddStringToObject(info->root, COMMAND_TOPIC_KEY, g_hassBuffer); //command_topic - - break; - - case ENTITY_SENSOR: -#ifndef OBK_DISABLE_ALL_DRIVERS - info = hass_init_device_info(type, index, "1", "0"); - - //https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes - //device_class automatically assigns unit,icon - if ((index >= OBK_VOLTAGE) && (index <= OBK_POWER)) - { - cJSON_AddStringToObject(info->root, "dev_cla", sensor_mqttNames[index]); //device_class=voltage,current,power - - sprintf(g_hassBuffer, "%s/%s/get", clientId, sensor_mqttNames[index]); - cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); - } - if ((index >= OBK_CONSUMPTION_TOTAL) && (index <= OBK_CONSUMPTION_STATS)) - { - cJSON_AddStringToObject(info->root, "dev_cla", counter_devClasses[index - OBK_CONSUMPTION_TOTAL]); //device_class=consumption - - sprintf(g_hassBuffer, "%s/%s/get", clientId, counter_mqttNames[index - OBK_CONSUMPTION_TOTAL]); - cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); - } -#endif + case ENTITY_LIGHT_PWMCW: + brightness_scale = 99; + //Using `last` (the default) will send any style (brightness, color, etc) topics first and then a payload_on to the command_topic. + //Using `first` will send the payload_on and then any style topics. + //Using `brightness` will only send brightness commands instead of the payload_on to turn the light on. + cJSON_AddStringToObject(info->root, "on_cmd_type", "first"); //on_command_type break; default: addLogAdv(LOG_ERROR, LOG_FEATURE_HASS, "Unsupported light type %s", type); } + if ((type == ENTITY_LIGHT_PWMCW) || (type == ENTITY_LIGHT_RGBCW)) { + sprintf(g_hassBuffer, "cmnd/%s/led_temperature", clientId); + 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 + } + + cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, "~/led_enableAll/get"); //state_topic + sprintf(g_hassBuffer, "cmnd/%s/led_enableAll", clientId); + cJSON_AddStringToObject(info->root, COMMAND_TOPIC_KEY, g_hassBuffer); //command_topic + + cJSON_AddStringToObject(info->root, "bri_stat_t", "~/led_dimmer/get"); //brightness_state_topic + sprintf(g_hassBuffer, "cmnd/%s/led_dimmer", clientId); + cJSON_AddStringToObject(info->root, "bri_cmd_t", g_hassBuffer); //brightness_command_topic + + cJSON_AddNumberToObject(info->root, "bri_scl", brightness_scale); //brightness_scale + return info; } +#ifndef OBK_DISABLE_ALL_DRIVERS + +/// @brief Initializes HomeAssistant sensor device discovery storage. +/// @param index Index corresponding to sensor_mqttNames. +/// @return +HassDeviceInfo* hass_init_sensor_device_info(int index) { + const char* clientId = CFG_GetMQTTClientId(); + HassDeviceInfo* info = hass_init_device_info(ENTITY_SENSOR, index, NULL, NULL); + + //https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes + //device_class automatically assigns unit,icon + if ((index >= OBK_VOLTAGE) && (index <= OBK_POWER)) + { + cJSON_AddStringToObject(info->root, "dev_cla", sensor_mqttNames[index]); //device_class=voltage,current,power + + sprintf(g_hassBuffer, "%s/%s/get", clientId, sensor_mqttNames[index]); + cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); + } + if ((index >= OBK_CONSUMPTION_TOTAL) && (index <= OBK_CONSUMPTION_STATS)) + { + cJSON_AddStringToObject(info->root, "dev_cla", counter_devClasses[index - OBK_CONSUMPTION_TOTAL]); //device_class=consumption + + sprintf(g_hassBuffer, "%s/%s/get", clientId, counter_mqttNames[index - OBK_CONSUMPTION_TOTAL]); + cJSON_AddStringToObject(info->root, STATE_TOPIC_KEY, g_hassBuffer); + } + + //state_class can be measurement, total or total_increasing. Something like daily power consumption could be total_increasing. + cJSON_AddStringToObject(info->root, "stat_cla", "measurement"); + + return info; +} + +#endif + /// @brief Returns the discovery JSON. /// @param info /// @return diff --git a/src/httpserver/hass.h b/src/httpserver/hass.h index c957288fe..a5c59d33c 100644 --- a/src/httpserver/hass.h +++ b/src/httpserver/hass.h @@ -5,11 +5,23 @@ #include "../mqtt/new_mqtt.h" typedef enum { + /// @brief Switch ENTITY_RELAY = 0, - ENTITY_LIGHT_PWM = 1, - ENTITY_LIGHT_RGB = 2, - ENTITY_LIGHT_RGBCW = 3, - ENTITY_SENSOR = 4, + + /// @brief Single PWM + ENTITY_LIGHT_PWM, + + /// @brief 2 PWM setup (brightness and temperature) + ENTITY_LIGHT_PWMCW, + + /// @brief RGB + ENTITY_LIGHT_RGB, + + /// @brief RGB + temperature + ENTITY_LIGHT_RGBCW, + + /// @brief Sensor (voltage, current, power) + ENTITY_SENSOR } ENTITY_TYPE; //unique_id is defined in hass_populate_unique_id and is based on CFG_GetDeviceName() whose size is CGF_DEVICE_NAME_SIZE. @@ -36,6 +48,7 @@ typedef struct HassDeviceInfo_s { void hass_print_unique_id(http_request_t* request, const char* fmt, ENTITY_TYPE type, int index); HassDeviceInfo* hass_init_relay_device_info(int index); -HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type, int index); +HassDeviceInfo* hass_init_light_device_info(ENTITY_TYPE type); +HassDeviceInfo* hass_init_sensor_device_info(int index); char* hass_build_discovery_json(HassDeviceInfo* info); void hass_free_device_info(HassDeviceInfo* info); diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index 9dcd61b8c..8981e530a 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -92,9 +92,9 @@ template_t g_templates[] = { { Setup_Device_Enbrighten_WFD4103, "Enbrighten WFD4103 WiFi Switch BK7231T WB2S"} , { Setup_Device_Zemismart_Light_Switch_KS_811_3, "Zemismart Light Switch (Neutral Optional) KS_811_3"} , { Setup_Device_TeslaSmartPlus_TSL_SPL_1, "Tesla Smart Plug. Model: (TSL-SPL-1)"}, - { Setup_Device_Calex_900011_1_WB2S, "Calex Smart Power Plug 900011.1"}, - { Setup_Device_Immax_NEO_LITE_NAS_WR07W, "Immax NEO Lite. Model: (NAS-WR07W)"} , - { Setup_Device_MOES_TouchSwitch_WS_EU1_RFW_N, "MOES Touch Switch 1gang Model:(WS-EU1-RFW-N)"} + { Setup_Device_Calex_900011_1_WB2S, "Calex Smart Power Plug 900011.1"}, + { Setup_Device_Immax_NEO_LITE_NAS_WR07W, "Immax NEO Lite. Model: (NAS-WR07W)"} , + { Setup_Device_MOES_TouchSwitch_WS_EU1_RFW_N, "MOES Touch Switch 1gang Model:(WS-EU1-RFW-N)"} }; int g_total_templates = sizeof(g_templates) / sizeof(g_templates[0]); @@ -549,33 +549,34 @@ int http_fn_index(http_request_t* request) { hprintf128(request, "MQTT Stats:CONN: %d PUB: %d RECV: %d ERR: %d ", MQTT_GetConnectEvents(), MQTT_GetPublishEventCounter(), MQTT_GetReceivedEventCounter(), MQTT_GetPublishErrorCounter()); - /* Format current PINS input state for all unused pins */ - if(CFG_HasFlag(OBK_FLAG_HTTP_PINMONITOR)) - { - for (i=0;i<29;i++) - { - if ((PIN_GetPinRoleForPinIndex(i) == IOR_None) && (i!=10) && (i!=11)) - { - HAL_PIN_Setup_Input(i); - } - } - - hprintf128(request,"