mirror of
https://github.com/openshwprojects/OpenBK7231T_App.git
synced 2026-02-07 02:05:46 +00:00
Add ChType_Enum and enable SetChannelEnum. (#1830)
* create a ChType_Enum to go with SetChannelEnum * resolve build errors for ChType_Enum PR * fixing build errors for simulator and others for cmd_enums.c * added ChType_ReadOnlyEnum and assocaited enum selftests * ChType_Enum simulation and memory error corrections * ChType_Enum documentation updates --------- Co-authored-by: root <root@stonacek.nz>
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
#include "../hal/hal_wifi.h"
|
||||
#include "../driver/drv_public.h"
|
||||
#include "../new_pins.h"
|
||||
#include "../cmnds/cmd_enums.h"
|
||||
|
||||
#if ENABLE_HA_DISCOVERY
|
||||
|
||||
@ -134,6 +135,9 @@ void hass_populate_unique_id(ENTITY_TYPE type, int index, char* uniq_id, int ase
|
||||
case HASS_BUTTON:
|
||||
sprintf(uniq_id, "%s_%s", longDeviceName, "button");
|
||||
break;
|
||||
case HASS_SELECT:
|
||||
sprintf(uniq_id, "%s_%s", longDeviceName, "select");
|
||||
break;
|
||||
default:
|
||||
// TODO: USE type here as well?
|
||||
// If type is not set, and we use "sensor" naming, we can easily make collision
|
||||
@ -322,6 +326,19 @@ static void generate_command_template(int numoptions, const char* options[], cha
|
||||
|
||||
HassDeviceInfo* hass_createSelectEntityIndexed(const char* state_topic, const char* command_topic, int numoptions,
|
||||
const char* options[], const char* title) {
|
||||
|
||||
char value_template[512];
|
||||
generate_value_template(numoptions, options, value_template, sizeof(value_template));
|
||||
|
||||
char command_template[512];
|
||||
generate_command_template(numoptions, options, command_template, sizeof(command_template));
|
||||
|
||||
return hass_createSelectEntityIndexedCustom(state_topic, command_topic, numoptions, options, title,
|
||||
value_template, command_template);
|
||||
}
|
||||
|
||||
HassDeviceInfo* hass_createSelectEntityIndexedCustom(const char* state_topic, const char* command_topic, int numoptions,
|
||||
const char* options[], const char* title, char* value_template, char* command_template) {
|
||||
HassDeviceInfo* info = hass_init_device_info(HASS_SELECT, 0, NULL, NULL, 0, title);
|
||||
|
||||
cJSON_AddStringToObject(info->root, "name", title);
|
||||
@ -335,17 +352,14 @@ HassDeviceInfo* hass_createSelectEntityIndexed(const char* state_topic, const ch
|
||||
}
|
||||
cJSON_AddItemToObject(info->root, "options", select_options);
|
||||
|
||||
char value_template[512];
|
||||
generate_value_template(numoptions, options, value_template, sizeof(value_template));
|
||||
cJSON_AddStringToObject(info->root, "value_template", value_template);
|
||||
|
||||
char command_template[512];
|
||||
generate_command_template(numoptions, options, command_template, sizeof(command_template));
|
||||
cJSON_AddStringToObject(info->root, "command_template", command_template);
|
||||
|
||||
cJSON_AddStringToObject(info->root, "availability_topic", "~/status");
|
||||
cJSON_AddStringToObject(info->root, "payload_available", "online");
|
||||
cJSON_AddStringToObject(info->root, "payload_not_available", "offline");
|
||||
if (!CFG_HasFlag(OBK_FLAG_NOT_PUBLISH_AVAILABILITY)) {
|
||||
cJSON_AddStringToObject(info->root, "availability_topic", "~/connected");
|
||||
cJSON_AddStringToObject(info->root, "payload_available", "online");
|
||||
cJSON_AddStringToObject(info->root, "payload_not_available", "offline");
|
||||
}
|
||||
|
||||
sprintf(info->channel, "select/%s/config", info->unique_id);
|
||||
|
||||
@ -572,7 +586,7 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, const char* p
|
||||
case HASS_BUTTON:
|
||||
sprintf(g_hassBuffer, "%s" , "");
|
||||
break;
|
||||
|
||||
case HASS_READONLYENUM:
|
||||
default:
|
||||
sprintf(g_hassBuffer, "%s", CHANNEL_GetLabel(index));
|
||||
break;
|
||||
@ -607,6 +621,12 @@ HassDeviceInfo* hass_init_device_info(ENTITY_TYPE type, int index, const char* p
|
||||
}
|
||||
}
|
||||
|
||||
if (type == HASS_READONLYENUM) {
|
||||
char value_template[1024];
|
||||
CMD_GenEnumValueTemplate(g_enums[index], value_template, sizeof(value_template));
|
||||
cJSON_AddStringToObject(info->root, "value_template", value_template);
|
||||
}
|
||||
|
||||
cJSON_AddStringToObject(info->root, "uniq_id", info->unique_id); //unique_id
|
||||
cJSON_AddNumberToObject(info->root, "qos", 1);
|
||||
|
||||
@ -1012,6 +1032,11 @@ HassDeviceInfo* hass_init_sensor_device_info(ENTITY_TYPE type, int channel, int
|
||||
sprintf(g_hassBuffer, "~/%d/get", channel);
|
||||
cJSON_AddStringToObject(info->root, "stat_t", g_hassBuffer);
|
||||
break;
|
||||
case HASS_READONLYENUM:
|
||||
sprintf(g_hassBuffer, "~/%d/get", channel);
|
||||
cJSON_AddStringToObject(info->root, "stat_t", g_hassBuffer);
|
||||
// str sensor can't have state_class, so return before it gets set
|
||||
return info;
|
||||
case CUSTOM_SENSOR:
|
||||
sprintf(g_hassBuffer, "~/%d/get", channel);
|
||||
cJSON_AddStringToObject(info->root, "stat_t", g_hassBuffer);
|
||||
|
||||
@ -101,6 +101,8 @@ typedef enum {
|
||||
HASS_PERCENT,
|
||||
HASS_TEXTFIELD,
|
||||
HASS_BUTTON,
|
||||
// @Brief ChType_ReadOnlyEnum, readonly with value_template
|
||||
HASS_READONLYENUM,
|
||||
} ENTITY_TYPE;
|
||||
|
||||
typedef enum {
|
||||
@ -145,6 +147,8 @@ HassDeviceInfo* hass_createSelectEntity(const char* state_topic, const char* com
|
||||
const char* options[], const char* title);
|
||||
HassDeviceInfo* hass_createSelectEntityIndexed(const char* state_topic, const char* command_topic, int numoptions,
|
||||
const char* options[], const char* title);
|
||||
HassDeviceInfo* hass_createSelectEntityIndexedCustom(const char* state_topic, const char* command_topic, int numoptions,
|
||||
const char* options[], const char* title, char* value_template, char* command_template);
|
||||
|
||||
HassDeviceInfo* hass_createToggle(const char *label, const char *stateTopic, const char *commandTopic);
|
||||
HassDeviceInfo* hass_init_textField_info(int index);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "../hal/hal_ota.h"
|
||||
// Commands register, execution API and cmd tokenizer
|
||||
#include "../cmnds/cmd_public.h"
|
||||
#include "../cmnds/cmd_enums.h"
|
||||
#include "../driver/drv_tuyaMCU.h"
|
||||
#include "../driver/drv_public.h"
|
||||
#include "../driver/drv_bl_shared.h"
|
||||
@ -495,6 +496,56 @@ int http_fn_index(http_request_t* request) {
|
||||
hprintf255(request, "Channel %s = %i", CHANNEL_GetLabel(i), iValue);
|
||||
}
|
||||
poststr(request, "</td></tr>");
|
||||
} else if (channelType == ChType_Enum) {
|
||||
iValue = CHANNEL_Get(i);
|
||||
channelEnum_t *en;
|
||||
|
||||
|
||||
// if setChannelEnum has not been defined, treat ChType_Enum as a textfield
|
||||
if (g_enums == NULL || g_enums[i]->numOptions == 0 ) {
|
||||
//en = g_enums[i];
|
||||
poststr(request, "<tr><td>");
|
||||
hprintf255(request, "<p>Change channel %s enum:</p><form action=\"index\">", CHANNEL_GetLabel(i));
|
||||
hprintf255(request, "<input type=\"hidden\" name=\"setIndex\" value=\"%i\">", i);
|
||||
hprintf255(request, "<input type=\"number\" name=\"set\" value=\"%i\" onblur=\"this.form.submit()\">", iValue);
|
||||
hprintf255(request, "<input type=\"submit\" value=\"Set!\"/></form>");
|
||||
hprintf255(request, "</form>");
|
||||
poststr(request, "</td></tr>");
|
||||
} else {
|
||||
en = g_enums[i];
|
||||
|
||||
poststr(request, "<tr><td>");
|
||||
hprintf255(request, "<form action=\"index\"><label for=\"select%i\">Channel %s Enum:</label>", i, CHANNEL_GetLabel(i));
|
||||
hprintf255(request, "<input type=\"hidden\" name=\"setIndex\" value=\"%i\">", i);
|
||||
hprintf255(request, "<select id=\"select%i\" name=\"set\" onchange=\"this.form.submit()\">", i);
|
||||
|
||||
bool found = false;
|
||||
for (int o = 0; o < en->numOptions; o++) {
|
||||
const char* selected;
|
||||
if (en->options[o].value == iValue) {
|
||||
selected = "selected";
|
||||
found = true;
|
||||
} else
|
||||
selected = "";
|
||||
hprintf255(request, "<option value=\"%i\" %s>%s [%i]</option>", en->options[o].value, selected, en->options[o].label,en->options[o].value);
|
||||
}
|
||||
if (!found) // create an item if no label is found
|
||||
hprintf255(request, "<option value=\"%i\" selected>undefined enum [%i]</option>", iValue,iValue);
|
||||
hprintf255(request, "</select></form>");
|
||||
poststr(request, "</td></tr>");
|
||||
}
|
||||
}
|
||||
else if (channelType == ChType_ReadOnlyEnum) {
|
||||
iValue = CHANNEL_Get(i);
|
||||
const char* oLabel;
|
||||
if (g_enums == NULL || g_enums[i]->numOptions == 0)
|
||||
oLabel = CHANNEL_GetLabel(i);
|
||||
else
|
||||
oLabel = CMD_FindChannelEnumLabel(g_enums[i], iValue);
|
||||
|
||||
poststr(request, "<tr><td>");
|
||||
hprintf255(request, "Channel %s = %s [%i]", CHANNEL_GetLabel(i), oLabel, iValue);
|
||||
poststr(request, "</td></tr>");
|
||||
}
|
||||
else if ((types = Channel_GetOptionsForChannelType(channelType, &numTypes)) != 0) {
|
||||
const char *what;
|
||||
@ -2236,6 +2287,54 @@ void doHomeAssistantDiscovery(const char* topic, http_request_t* request) {
|
||||
dev_info = hass_init_textField_info(i);
|
||||
}
|
||||
break;
|
||||
case ChType_ReadOnlyEnum:
|
||||
{
|
||||
dev_info = hass_init_sensor_device_info(HASS_READONLYENUM, i, -1, -1, -1);
|
||||
}
|
||||
break;
|
||||
case ChType_Enum:
|
||||
{
|
||||
channelEnum_t *en;
|
||||
if (g_enums != NULL && g_enums[i]->numOptions != 0) {
|
||||
en = g_enums[i];
|
||||
} else {
|
||||
// revert to textfield if no enums are defined
|
||||
dev_info = hass_init_textField_info(i);
|
||||
break;
|
||||
}
|
||||
|
||||
char **options=(char**)malloc(en->numOptions * sizeof(char *));
|
||||
for (int o = 0; o < en->numOptions; o++) {
|
||||
options[o] = en->options[o].label;
|
||||
}
|
||||
|
||||
if (en->options != NULL && en->numOptions >0) {
|
||||
// backlog setChannelType 1 Enum; setChannelEnum 0:red 2:blue 3:green; scheduleHADiscovery 1
|
||||
char stateTopic[32];
|
||||
char cmdTopic[32];
|
||||
char title[64];
|
||||
char value_tmp[1024];
|
||||
char command_tmp[1024];
|
||||
|
||||
CMD_GenEnumValueTemplate(en, value_tmp, sizeof(value_tmp));
|
||||
CMD_GenEnumCommandTemplate(en, command_tmp, sizeof(command_tmp));
|
||||
|
||||
strcpy(title, CHANNEL_GetLabel(i));
|
||||
sprintf(stateTopic, "~/%i/get", i);
|
||||
sprintf(cmdTopic, "~/%i/set", i);
|
||||
dev_info = hass_createSelectEntityIndexedCustom(
|
||||
stateTopic,
|
||||
cmdTopic,
|
||||
en->numOptions,
|
||||
(const char**)options,
|
||||
title,
|
||||
value_tmp,
|
||||
command_tmp
|
||||
);
|
||||
}
|
||||
os_free(options);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
int numOptions;
|
||||
|
||||
@ -325,7 +325,7 @@ void http_html_start(http_request_t* request, const char* pagename) {
|
||||
}
|
||||
|
||||
|
||||
const char pageScriptPart1[] = "<script type='text/javascript'>var firstTime,lastTime,onlineFor,req=null,onlineForEl=null,getElement=e=>document.getElementById(e);function showState(){clearTimeout(firstTime),clearTimeout(lastTime),null!=req&&req.abort(),(e=getElement(\"state\"))&&((req=new XMLHttpRequest).onreadystatechange=()=>{4==req.readyState&&\"OK\"==req.statusText&&((\"INPUT\"!=document.activeElement.tagName||\"number\"!=document.activeElement.type&&\"color\"!=document.activeElement.type)&&(e.innerHTML=req.responseText),clearTimeout(firstTime),clearTimeout(lastTime),lastTime=setTimeout(showState,";
|
||||
const char pageScriptPart1[] = "<script type='text/javascript'>var firstTime,lastTime,onlineFor,req=null,onlineForEl=null,getElement=e=>document.getElementById(e);function showState(){clearTimeout(firstTime),clearTimeout(lastTime),null!=req&&req.abort(),(e=getElement(\"state\"))&&((req=new XMLHttpRequest).onreadystatechange=()=>{4==req.readyState&&\"OK\"==req.statusText&&(\"SELECT\"!=document.activeElement.tagName&&(\"INPUT\"!=document.activeElement.tagName||\"number\"!=document.activeElement.type&&\"color\"!=document.activeElement.type)&&(e.innerHTML=req.responseText),clearTimeout(firstTime),clearTimeout(lastTime),lastTime=setTimeout(showState,";
|
||||
const char pageScriptPart2[] = "))},req.open(\"GET\",\"index?state=1\",!0),req.send()),firstTime=setTimeout(showState,";
|
||||
const char pageScriptPart3[] = ")}function fmtUpTime(e){var t,n,o=Math.floor(e/86400);return e%=86400,t=Math.floor(e/3600),e%=3600,n=Math.floor(e/60),e=e%60,0<o?o+` days, ${t} hours, ${n} minutes and ${e} seconds`:0<t?t+` hours, ${n} minutes and ${e} seconds`:0<n?n+` minutes and ${e} seconds`:`just ${e} seconds`}function updateOnlineFor(){onlineForEl.textContent=fmtUpTime(++onlineFor)}function onLoad(){(onlineForEl=getElement(\"onlineFor\"))&&(onlineFor=parseInt(onlineForEl.dataset.initial,10))&&setInterval(updateOnlineFor,1e3),showState()}function submitTemperature(e){var t=getElement(\"form132\");getElement(\"kelvin132\").value=Math.round(1e6/parseInt(e.value)),t.submit()}window.addEventListener(\"load\",onLoad),history.pushState(null,\"\",window.location.pathname.slice(1)),setTimeout(()=>{var e=getElement(\"changed\");e&&(e.innerHTML=\"\")},5e3);</script>";
|
||||
|
||||
|
||||
@ -21,8 +21,9 @@ function showState() {
|
||||
if (req.readyState == 4 && req.statusText == "OK") {
|
||||
if (
|
||||
!(
|
||||
document.activeElement.tagName == "INPUT" &&
|
||||
(document.activeElement.type == "number" || document.activeElement.type == "color")
|
||||
document.activeElement.tagName == "SELECT" &&
|
||||
(document.activeElement.tagName == "INPUT" &&
|
||||
(document.activeElement.type == "number" || document.activeElement.type == "color"))
|
||||
)
|
||||
) {
|
||||
var stateEl = getElement("state");
|
||||
|
||||
Reference in New Issue
Block a user