diff --git a/HMI/README.md b/HMI/README.md index 8b710e3b..4cd8da16 100644 --- a/HMI/README.md +++ b/HMI/README.md @@ -95,7 +95,7 @@ The following message can be used to update the content on the cardEntities Page `,text,sensor.entityName,3,17299,Temperature,content` -`button,button.entityName,3,17299,bt-name,bt-text` +`,button,button.entityName,3,17299,bt-name,bt-text` `,switch,switch.entityName,4,17299,Switch1,0` diff --git a/ioBroker/NsPanelTs.ts b/ioBroker/NsPanelTs.ts index 3d2f6139..d334d128 100644 --- a/ioBroker/NsPanelTs.ts +++ b/ioBroker/NsPanelTs.ts @@ -27,21 +27,84 @@ type Config = { dateFormat: string, weatherEntity: string | null, temperatureUnit: string, - batEntity: string, - pvEntity: string, - pages: (PageThermo | PageEntities)[] + leftEntity: string, + leftEntityIcon: number, + leftEntityText: string, + leftEntityUnitText: string | null, + rightEntity: string, + rightEntityIcon: number, + rightEntityText: string, + rightEntityUnitText: string | null, + pages: (PageThermo | PageEntities)[], + button1Page: (PageThermo | PageEntities | null), + button2Page: (PageThermo | PageEntities | null), } - var subscriptions: any = {}; var pageId = 0; +var page1: PageEntities = +{ + "type": "cardEntities", + "heading": "Haus", + "items": [ + "alias.0.Rolladen_Eltern", + "alias.0.Erker", + "alias.0.Küche", + "alias.0.Wand" + ] +}; + +var page2: PageEntities = +{ + "type": "cardEntities", + "heading": "Strom", + "items": [ + "alias.0.Netz", + "alias.0.Hausverbrauch", + "alias.0.Pv", + "alias.0.Batterie" + ] +}; + +var button1Page: PageEntities = +{ + "type": "cardEntities", + "heading": "Knopf1", + "items": [ + "alias.0.Schlafen", + "alias.0.Stern", + "delete", + "delete" + ] +}; + + +var button2Page: PageEntities = +{ + "type": "cardEntities", + "heading": "Knopf2", + "items": [ + "delete", + "delete", + "alias.0.Schlafen", + "alias.0.Stern" + + ] +}; + var config: Config = { panelRecvTopic: "mqtt.0.tele.WzDisplay.RESULT", panelSendTopic: "mqtt.0.cmnd.WzDisplay.CustomSend", - batEntity: "alias.0.Batterie.ACTUAL", - pvEntity: "alias.0.Pv.ACTUAL", + leftEntity: "alias.0.Batterie.ACTUAL", + leftEntityIcon: 34, + leftEntityText: "Batterie", + leftEntityUnitText: "%", + rightEntity: "alias.0.Pv.ACTUAL", + rightEntityIcon: 32, + rightEntityText: "PV", + rightEntityUnitText: "W", timeoutScreensaver: 15, dimmode: 8, locale: "de_DE", @@ -50,33 +113,16 @@ var config: Config = { weatherEntity: "alias.0.Wetter", temperatureUnit: "°C", - pages: [ - { - "type": "cardEntities", - "heading": "Haus", - "items": [ - "alias.0.Rolladen_Eltern", - "alias.0.Erker", - "alias.0.Küche", - "alias.0.Wand" - ] - }, - { - "type": "cardEntities", - "heading": "Strom", - "items": [ - "alias.0.Netz", - "alias.0.Hausverbrauch", - "alias.0.Pv", - "alias.0.Batterie" - ] - }, + pages: [page1, page2, + { "type": "cardThermo", "heading": "Thermostat", "item": "alias.0.WzNsPanel" } - ] + ], + button1Page: button1Page, + button2Page: button2Page }; schedule("* * * * *", function () { @@ -86,10 +132,20 @@ schedule("0 * * * *", function () { SendDate(); }); -on([config.pvEntity, config.batEntity], function () { - HandleScreensaverUpdate(); -}) +// Only monitor the extra nodes if one or both are present +var updateArray: string[] = []; +if (config.rightEntity !== null && existsState(config.rightEntity)) { + updateArray.push(config.rightEntity) +} +if (config.leftEntity !== null && existsState(config.leftEntity)) { + updateArray.push(config.leftEntity) +} +if (updateArray.length > 0) { + on(updateArray, function () { + HandleScreensaverUpdate(); + }) +} on({ id: config.panelRecvTopic }, function (obj) { if (obj.state.val.startsWith('\{"CustomRecv":')) { var json = JSON.parse(obj.state.val); @@ -123,15 +179,11 @@ function HandleMessage(typ: string, method: string, page: number, words: Array = []; - if (config.pages[pageId].type == "cardEntities") { - retMsgs = GenerateEntitiesPage(pageId, config.pages[pageId]) - } else if (config.pages[pageId].type == "cardThermo") { - retMsgs = GenerateThermoPage(pageId, config.pages[pageId]) - } + if (method == 'startup') HandleStartupProcess(); - SendToPanel(retMsgs) + + GeneratePage(config.pages[pageId]); } if (method == 'buttonPress' || method == "tempUpd") { @@ -141,6 +193,43 @@ function HandleMessage(typ: string, method: string, page: number, words: Array = []; + if (page.type == "cardEntities") { + retMsgs = GenerateEntitiesPage(config.pages[pageId]) + } else if (page.type == "cardThermo") { + retMsgs = GenerateThermoPage(pageId, config.pages[pageId]) + } + + SendToPanel(retMsgs) +} + +function HandleHardwareButton(method: string): void { + let page: (PageThermo | PageEntities); + if (config.button1Page !== null && method == "button1") { + page = config.button1Page; + } + else if (config.button2Page !== null && method == "button2") { + page = config.button2Page; + } + else { + return; + } + SendToPanel({ payload: "wake" }); + switch (page.type) { + case "cardEntities": + SendToPanel(GenerateEntitiesPage(page)); + break; + case "cardThermo": + SendToPanel(GenerateThermoPage(0, page)); + break; } } @@ -178,22 +267,23 @@ function SendTime(): void { SendToPanel({ payload: "time," + hr + ":" + min }); } -function GenerateEntitiesPage(pageNum: number, page: PageEntities): Payload[] { +function GenerateEntitiesPage(page: PageEntities): Payload[] { var out_msgs: Array = []; - out_msgs = [{ payload: "pageType,cardEntities" }, { payload: "entityUpdHeading," + config.pages[pageNum].heading }] - + out_msgs = [{ payload: "pageType,cardEntities" }, { payload: "entityUpdHeading," + page.heading }] + let pageData = "entityUpd"; page.items.forEach(function (id, i) { - out_msgs.push(CreateEntity(id, i + 1)); + pageData += CreateEntity(id, i + 1); }) + out_msgs.push({ payload: pageData }); return out_msgs } -function CreateEntity(id: string, placeId: number): Payload { +function CreateEntity(id: string, placeId: number): string { var type = "delete" var iconId = 0 var name = "FriendlyName" if (id == "delete") { - return { payload: "entityUpd," + placeId + "," + type }; + return ",delete,,,," } // ioBroker @@ -217,7 +307,7 @@ function CreateEntity(id: string, placeId: number): Payload { var optVal = "0" if (val === true || val === "true") optVal = "1" - return { payload: "entityUpd," + placeId + "," + type + "," + id + "," + iconId + "," + name + "," + optVal } + return "," + type + "," + id + "," + iconId + "," + "17299," + name + "," + optVal case "dimmer": type = "light" @@ -233,12 +323,12 @@ function CreateEntity(id: string, placeId: number): Payload { } if (val === true || val === "true") optVal = "1" - return { payload: "entityUpd," + placeId + "," + type + "," + id + "," + iconId + "," + name + "," + optVal } + return "," + type + "," + id + "," + iconId + "," + "17299," + name + "," + optVal case "blind": type = "shutter" iconId = 0 - return { payload: "entityUpd," + placeId + "," + type + "," + id + "," + iconId + "," + name } + return "," + type + "," + id + "," + iconId + "," + "17299," + name + "," case "info": case "value.temperature": @@ -261,19 +351,21 @@ function CreateEntity(id: string, placeId: number): Payload { else { optVal += GetUnitOfMeasurement(id + ".ACTUAL"); } - return { payload: "entityUpd," + placeId + "," + type + "," + id + "," + iconId + "," + name + "," + optVal }; + return "," + type + "," + id + "," + iconId + "," + "17299," + name + "," + optVal; case "button": type = "button"; iconId = 3; var optVal = "PRESS"; - return { payload: "entityUpd," + placeId + "," + type + "," + id + "," + iconId + "," + name + "," + optVal }; + return "," + type + "," + id + "," + iconId + "," + "17299," + name + "," + optVal; default: - break + return ",delete,,,," + } } - return { payload: "entityUpd," + placeId + "," + type }; + + return ",delete,,,," } function RegisterEntityWatcher(id: string, entityId: string, placeId: number): void { @@ -281,7 +373,7 @@ function RegisterEntityWatcher(id: string, entityId: string, placeId: number): v return; } subscriptions[id] = (on({ id: id, change: 'any' }, function (data) { - SendToPanel(CreateEntity(entityId, placeId)); + GeneratePage(config.pages[pageId]); })) } @@ -392,6 +484,7 @@ function GenerateDetailPage(type: string, entityId: string): Payload[] { if (existsObject(id)) { var o = getObject(id) var val = null; + let icon = 1; if (type == "popupLight") { let switchVal = "0" if (o.common.role == "light") { @@ -406,8 +499,8 @@ function GenerateDetailPage(type: string, entityId: string): Payload[] { if (val) switchVal = "1" - - out_msgs.push({ payload: "entityUpdateDetail," + switchVal + ",disable,disable,disable" }) + + out_msgs.push({ payload: "entityUpdateDetail," + icon + "," + "17299," + switchVal + ",disable,disable,disable" }) } if (o.common.role == "dimmer") { @@ -433,7 +526,7 @@ function GenerateDetailPage(type: string, entityId: string): Payload[] { //if (attr_support_color.includes("color_temp")) // colortemp = Math.trunc(scale(attr.color_temp, attr.min_mireds, attr.max_mireds, 0, 100)) - out_msgs.push({ payload: "entityUpdateDetail," + switchVal + "," + brightness + "," + colortemp }) + out_msgs.push({ payload: "entityUpdateDetail," + icon + "," + "17299," + switchVal + "," + brightness + "," + colortemp }) } } @@ -469,12 +562,37 @@ function HandleScreensaverUpdate(): void { if (config.weatherEntity != null && existsObject(config.weatherEntity)) { var icon = getState(config.weatherEntity + ".ICON").val; - let temperature: string = getState(config.weatherEntity + ".TEMP").val; + let temperature: string = + existsState(config.weatherEntity + ".ACTUAL") ? getState(config.weatherEntity + ".ACTUAL").val : + existsState(config.weatherEntity + ".TEMP") ? getState(config.weatherEntity + ".TEMP").val: "null"; let humidity = getState(config.weatherEntity + ".HUMIDITY").val; - let u1 = getState(config.batEntity).val; - let u2 = getState(config.pvEntity).val; - SendToPanel({ payload: "weatherUpdate,?" + GetAccuWeatherIcon(parseInt(icon)) + "?" + temperature.toString() + " " + config.temperatureUnit + "?26?" + humidity + " %?Batterie?34?" + u1 + "%?PV?32?" + u2 + "W" }) + + let payloadString = + "weatherUpdate,?" + GetAccuWeatherIcon(parseInt(icon)) + "?" + + temperature + " " + config.temperatureUnit + "?26?" + + humidity + " %?" ; + + if(existsState(config.leftEntity)) + { + let u1 = getState(config.leftEntity).val; + payloadString += config.leftEntityText + "?" + config.leftEntityIcon + "?" + u1 + " " + config.leftEntityUnitText + "?"; + } + else + { + payloadString += "???"; + } + + if(existsState(config.rightEntity)) + { + let u2 = getState(config.rightEntity).val; + payloadString += config.rightEntityText + "?" + config.rightEntityIcon + "?" + u2 + " " + config.rightEntityUnitText; + } + else + { + payloadString += "??"; + } + SendToPanel({ payload: payloadString}); } } diff --git a/ioBroker/README.md b/ioBroker/README.md index ef1593a4..12f06f65 100644 --- a/ioBroker/README.md +++ b/ioBroker/README.md @@ -24,8 +24,13 @@ You can find this in the device raw settings. ## Installation - Import this script into the ioBroker javascript instance and choose Typescript. +- Make sure the version of the adapter is not to old. - Find the config variable and update to your needs. - The format strings are not used right now. +- Make sure your device is connected with the mqtt instance. I didn't get it working with the sonoff adapter, but I didn't tried it too long. +- Create a state with a mqtt client or create one per hand. The mqtt adapter will not create the state CustomSend + - you only need to send a dummy message to cmnd//CustomSend + - then the state will be created ## Update the screensaver string The screensaver string which is send to the display looks something like this: @@ -37,21 +42,16 @@ See the icons currently usable in the following table: [Icon Table](../HMI#icons-ids) -You can change the string in this function: +You can change the string and devices in the config object. + +## Buttons +If you like you can add special pages for the buttons, but there is a problem currently which will open the last page again. But if you press the button again, the correct page will open. + +First you need to add this rule to Tasmota: + ``` -function HandleScreensaverUpdate(): void { - if (config.weatherEntity != null && existsObject(config.weatherEntity)) { - var icon = getState(config.weatherEntity + ".ICON").val; - - let temperature: string = getState(config.weatherEntity + ".TEMP").val; - let humidity = getState(config.weatherEntity + ".HUMIDITY").val; - let u1 = getState(config.batEntity).val; - let u2 = getState(config.pvEntity).val; - - SendToPanel({ payload: "weatherUpdate,?" + GetAccuWeatherIcon(parseInt(icon)) + "?" + temperature.toString() + " " + config.temperatureUnit + "?26?" + humidity + " %?Batterie?4?" + u1 + "%?PV?23?" + u2 + "W" }) - } -} - +Rule2 on Button1#state do Publish tele/%topic%/RESULT {"CustomRecv":"event,button1"} endon on Button2#state do Publish tele/%topic%/RESULT {"CustomRecv":"event,button2"} endon +Rule2 ``` ## The config element in the script which needs to be configured @@ -59,11 +59,14 @@ function HandleScreensaverUpdate(): void { var config: Config = { panelRecvTopic: "mqtt.0.tele.WzDisplay.RESULT", // This is the object where the panel send the data to. panelSendTopic: "mqtt.0.cmnd.WzDisplay.CustomSend", // This is the object where data is send to the panel. - batEntity: "alias.0.Batterie.ACTUAL", // This is a state which can be used to display the battery state. - pvEntity: "alias.0.Pv.ACTUAL", // This is a state which can be used to display the current solar yield. - // Both values are send via the HandleScreensaverUpdate() function, you need to update this string to your needs. - // Currently the icons are hardcoded. - + leftEntity: "alias.0.Batterie.ACTUAL", // This is a state will be displayed on the left side. + leftEntityIcon: 34, // This is a icon which will be displayed on the left side. + leftEntityText: "Batterie", // The label for the left side. + leftEntityUnitText: "%", // The unit which will be appendon the left side. + rightEntity: "alias.0.Pv.ACTUAL", // The same but for the right side. + rightEntityIcon: 32, + rightEntityText: "PV", + rightEntityUnitText: "W", timeoutScreensaver: 15, // Timeout for screensaver dimmode: 8, // Display dim locale: "de_DE", // not used right now @@ -100,7 +103,42 @@ var config: Config = { "heading": "Thermostat", "item": "alias.0.WzNsPanel" // Needs to be a thermostat in the device panel } + ], + button1Page: button1Page, // A cardEntities, cardThermo or nothing. This will be opened when pressing button1 + button2Page: button2Page // you guess it +}; +``` + +If you want you can create dedicated objects, so you don't need to declare them again. Then you can use tehm in the pages array and button pages. + +``` +var button1Page: PageEntities = +{ + "type": "cardEntities", + "heading": "Knopf1", + "items": [ + "alias.0.Schlafen", + "alias.0.Stern", + "delete", + "delete" ] }; ``` +Pages array can look like this: + +``` +pages: [ + button1Page, + { + "type": "cardEntities", + "heading": "Strom", + "items": [ + "alias.0.Netz", + "alias.0.Hausverbrauch", + "alias.0.Pv", + "alias.0.Batterie" + + ] + }] +``` \ No newline at end of file