mirror of
https://github.com/joBr99/nspanel-lovelace-ui.git
synced 2026-02-18 19:06:58 +01:00
Compare commits
2 Commits
v4.4.0
...
8eae83c8ba
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8eae83c8ba | ||
|
|
127671047f |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -58,5 +58,5 @@ _If applicable, add screenshots/pictures to help explain your problem._
|
||||
_Add any other context about the problem here._
|
||||
_Please note here in case you are using ioBroker_
|
||||
|
||||
### PANEL / FIRMWARE VERSION
|
||||
### PANEL / FIRMWARE VERION
|
||||
_Please add the Panel/Firmware Version you are using (EU, US-L or US-P)_
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
@@ -24,5 +24,5 @@ _A clear and concise description of what the feature should do._
|
||||
### ADDITIONAL CONTEXT
|
||||
_Add any other context about the problem here._
|
||||
|
||||
### PANEL / FIRMWARE VERSION
|
||||
### PANEL / FIRMWARE VERION
|
||||
_Please add the Panel/Firmware Version you are using (EU, US-L or US-P)_
|
||||
|
||||
4
.github/workflows/builder.yaml
vendored
4
.github/workflows/builder.yaml
vendored
@@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: env.BUILD_ARGS != '--test'
|
||||
uses: docker/login-action@v3.1.0
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
|
||||
- name: Build ${{ matrix.addon }} add-on
|
||||
if: steps.check.outputs.build_arch == 'true'
|
||||
uses: home-assistant/builder@2024.03.5
|
||||
uses: home-assistant/builder@2024.01.0
|
||||
with:
|
||||
args: |
|
||||
${{ env.BUILD_ARGS }} \
|
||||
|
||||
@@ -102,28 +102,6 @@
|
||||
│ crcputs sys0,2
|
||||
│ crcputs tSend.txt,0
|
||||
│ //send cmd
|
||||
│ --- HMI/n2t-out/popupLight.txt
|
||||
├── +++ HMI/US/landscape/n2t-out/popupLight.txt
|
||||
│ @@ -453,19 +453,14 @@
|
||||
│ ucopy strCommand.txt,4,payloadLength-5,0
|
||||
│ // write instruction to tInstuction (debug output, but used as variable here, ui elements will be disabled by default)
|
||||
│ spstr strCommand.txt,tInstruction.txt,"~",0
|
||||
│ spstr strCommand.txt,tTmp.txt,"~",1
|
||||
│ if(tInstruction.txt=="entityUpdateDetail"&&entn.txt==tTmp.txt)
|
||||
│ {
|
||||
│ // change icon
|
||||
│ - spstr strCommand.txt,tTmp.txt,"~",2
|
||||
│ - if(tTmp.txt!="")
|
||||
│ - {
|
||||
│ - tIcon1.txt=tTmp.txt
|
||||
│ - }
|
||||
│ //spstr strCommand.txt,tIcon1.txt,"~",2
|
||||
│ vis tIcon1,1
|
||||
│ // change icon color
|
||||
│ spstr strCommand.txt,tTmp.txt,"~",3
|
||||
│ covx tTmp.txt,sys0,0,0
|
||||
│ tIcon1.pco=sys0
|
||||
│ // get Button State
|
||||
│ --- HMI/n2t-out/popupNotify.txt
|
||||
├── +++ HMI/US/landscape/n2t-out/popupNotify.txt
|
||||
│ @@ -439,18 +439,14 @@
|
||||
@@ -543,3 +521,22 @@
|
||||
│ spstr strCommand.txt,tNotifyText.txt,"~",2
|
||||
│ if(tNotifyHead.txt!=""||tNotifyText.txt!="")
|
||||
│ {
|
||||
│ @@ -952,14 +812,18 @@
|
||||
│ {
|
||||
│ page cardPower
|
||||
│ }
|
||||
│ if(tId.txt=="cardChart")
|
||||
│ {
|
||||
│ page cardChart
|
||||
│ }
|
||||
│ + if(tId.txt=="cardLChart")
|
||||
│ + {
|
||||
│ + page cardLChart
|
||||
│ + }
|
||||
│ }
|
||||
│ if(tInstruction.txt=="timeout")
|
||||
│ {
|
||||
│ //set timeout to global var
|
||||
│ spstr strCommand.txt,tTmp.txt,"~",1
|
||||
│ covx tTmp.txt,sleepTimeout,0,0
|
||||
│ }
|
||||
|
||||
@@ -1985,26 +1985,6 @@
|
||||
│ Variable (string) entn
|
||||
│ Attributes
|
||||
│ Scope : local
|
||||
│ @@ -453,19 +453,14 @@
|
||||
│ ucopy strCommand.txt,4,payloadLength-5,0
|
||||
│ // write instruction to tInstuction (debug output, but used as variable here, ui elements will be disabled by default)
|
||||
│ spstr strCommand.txt,tInstruction.txt,"~",0
|
||||
│ spstr strCommand.txt,tTmp.txt,"~",1
|
||||
│ if(tInstruction.txt=="entityUpdateDetail"&&entn.txt==tTmp.txt)
|
||||
│ {
|
||||
│ // change icon
|
||||
│ - spstr strCommand.txt,tTmp.txt,"~",2
|
||||
│ - if(tTmp.txt!="")
|
||||
│ - {
|
||||
│ - tIcon1.txt=tTmp.txt
|
||||
│ - }
|
||||
│ //spstr strCommand.txt,tIcon1.txt,"~",2
|
||||
│ vis tIcon1,1
|
||||
│ // change icon color
|
||||
│ spstr strCommand.txt,tTmp.txt,"~",3
|
||||
│ covx tTmp.txt,sys0,0,0
|
||||
│ tIcon1.pco=sys0
|
||||
│ // get Button State
|
||||
│ --- HMI/n2t-out/popupNotify.txt
|
||||
├── +++ HMI/US/portrait/n2t-out/popupNotify.txt
|
||||
│ @@ -348,15 +348,15 @@
|
||||
@@ -2486,3 +2466,22 @@
|
||||
│ spstr strCommand.txt,tNotifyText.txt,"~",2
|
||||
│ if(tNotifyHead.txt!=""||tNotifyText.txt!="")
|
||||
│ {
|
||||
│ @@ -952,14 +800,18 @@
|
||||
│ {
|
||||
│ page cardPower
|
||||
│ }
|
||||
│ if(tId.txt=="cardChart")
|
||||
│ {
|
||||
│ page cardChart
|
||||
│ }
|
||||
│ + if(tId.txt=="cardLChart")
|
||||
│ + {
|
||||
│ + page cardLChart
|
||||
│ + }
|
||||
│ }
|
||||
│ if(tInstruction.txt=="timeout")
|
||||
│ {
|
||||
│ //set timeout to global var
|
||||
│ spstr strCommand.txt,tTmp.txt,"~",1
|
||||
│ covx tTmp.txt,sleepTimeout,0,0
|
||||
│ }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
+++ /dev/fd/62 2024-02-25 11:03:09.634837907 +0000
|
||||
+++ /dev/fd/62 2024-01-20 23:31:31.560618969 +0000
|
||||
+I/n2t-out/Program.s.txt
|
||||
++ HMI/US/portrait/n2t-out/Program.s.txt
|
||||
+1 +12,11 @@
|
||||
@@ -686,13 +686,6 @@
|
||||
+ covx tTmp.txt,sys0,0,0
|
||||
+ hSlider6.maxval=sys0
|
||||
+ }
|
||||
+ }
|
||||
+ if(tInstruction.txt=="pageType")
|
||||
+ {
|
||||
+ sleepValue=0
|
||||
+ //command format pageType,specialPageName
|
||||
+ //write name of speical page to tId
|
||||
+ spstr strCommand.txt,tId.txt,"~",1
|
||||
+I/n2t-out/cardGrid.txt
|
||||
++ HMI/US/portrait/n2t-out/cardGrid.txt
|
||||
+ +7,14 @@
|
||||
@@ -946,6 +939,13 @@
|
||||
+ spstr strCommand.txt,tEntity9.txt,"~",66
|
||||
+ vis tEntity9,1
|
||||
+ }
|
||||
+ }
|
||||
+ if(tInstruction.txt=="pageType")
|
||||
+ {
|
||||
+ sleepValue=0
|
||||
+ //command format pageType,specialPageName
|
||||
+ //write name of speical page to tId
|
||||
+ spstr strCommand.txt,tId.txt,"~",1
|
||||
+I/n2t-out/cardLChart.txt
|
||||
++ HMI/US/portrait/n2t-out/cardLChart.txt
|
||||
+ +7,14 @@
|
||||
@@ -1527,26 +1527,6 @@
|
||||
+e (string) entn
|
||||
+ributes
|
||||
+ Scope : local
|
||||
+19 +453,14 @@
|
||||
+ ucopy strCommand.txt,4,payloadLength-5,0
|
||||
+ // write instruction to tInstuction (debug output, but used as variable here, ui elements will be disabled by default)
|
||||
+ spstr strCommand.txt,tInstruction.txt,"~",0
|
||||
+ spstr strCommand.txt,tTmp.txt,"~",1
|
||||
+ if(tInstruction.txt=="entityUpdateDetail"&&entn.txt==tTmp.txt)
|
||||
+ {
|
||||
+ // change icon
|
||||
+ spstr strCommand.txt,tTmp.txt,"~",2
|
||||
+ if(tTmp.txt!="")
|
||||
+ {
|
||||
+ tIcon1.txt=tTmp.txt
|
||||
+ }
|
||||
+ //spstr strCommand.txt,tIcon1.txt,"~",2
|
||||
+ vis tIcon1,1
|
||||
+ // change icon color
|
||||
+ spstr strCommand.txt,tTmp.txt,"~",3
|
||||
+ covx tTmp.txt,sys0,0,0
|
||||
+ tIcon1.pco=sys0
|
||||
+ // get Button State
|
||||
+I/n2t-out/popupNotify.txt
|
||||
++ HMI/US/portrait/n2t-out/popupNotify.txt
|
||||
+15 +348,15 @@
|
||||
@@ -2028,3 +2008,22 @@
|
||||
+ spstr strCommand.txt,tNotifyText.txt,"~",2
|
||||
+ if(tNotifyHead.txt!=""||tNotifyText.txt!="")
|
||||
+ {
|
||||
+14 +800,18 @@
|
||||
+ {
|
||||
+ page cardPower
|
||||
+ }
|
||||
+ if(tId.txt=="cardChart")
|
||||
+ {
|
||||
+ page cardChart
|
||||
+ }
|
||||
+ if(tId.txt=="cardLChart")
|
||||
+ {
|
||||
+ page cardLChart
|
||||
+ }
|
||||
+ }
|
||||
+ if(tInstruction.txt=="timeout")
|
||||
+ {
|
||||
+ //set timeout to global var
|
||||
+ spstr strCommand.txt,tTmp.txt,"~",1
|
||||
+ covx tTmp.txt,sleepTimeout,0,0
|
||||
+ }
|
||||
|
||||
@@ -30,10 +30,6 @@ popupLightNew
|
||||
23 Component(s)
|
||||
412 Line(s) of event code
|
||||
209 Unique line(s) of event code
|
||||
popupLight
|
||||
28 Component(s)
|
||||
417 Line(s) of event code
|
||||
228 Unique line(s) of event code
|
||||
cardGrid2
|
||||
52 Component(s)
|
||||
703 Line(s) of event code
|
||||
@@ -58,6 +54,10 @@ cardLChart
|
||||
33 Component(s)
|
||||
412 Line(s) of event code
|
||||
267 Unique line(s) of event code
|
||||
popupLight
|
||||
28 Component(s)
|
||||
412 Line(s) of event code
|
||||
227 Unique line(s) of event code
|
||||
cardPower
|
||||
54 Component(s)
|
||||
541 Line(s) of event code
|
||||
@@ -66,6 +66,10 @@ cardThermo
|
||||
57 Component(s)
|
||||
550 Line(s) of event code
|
||||
320 Unique line(s) of event code
|
||||
screensaver2
|
||||
64 Component(s)
|
||||
424 Line(s) of event code
|
||||
264 Unique line(s) of event code
|
||||
popupInSel
|
||||
34 Component(s)
|
||||
621 Line(s) of event code
|
||||
@@ -86,10 +90,6 @@ popupThermo
|
||||
44 Component(s)
|
||||
523 Line(s) of event code
|
||||
276 Unique line(s) of event code
|
||||
screensaver2
|
||||
64 Component(s)
|
||||
428 Line(s) of event code
|
||||
266 Unique line(s) of event code
|
||||
cardEntities
|
||||
67 Component(s)
|
||||
1205 Line(s) of event code
|
||||
@@ -98,5 +98,5 @@ cardEntities
|
||||
Total
|
||||
23 Page(s)
|
||||
881 Component(s)
|
||||
10778 Line(s) of event code
|
||||
10769 Line(s) of event code
|
||||
2466 Unique line(s) of event code
|
||||
|
||||
@@ -806,11 +806,6 @@ Timer tmSerial
|
||||
if(tInstruction.txt=="entityUpdateDetail"&&entn.txt==tTmp.txt)
|
||||
{
|
||||
// change icon
|
||||
spstr strCommand.txt,tTmp.txt,"~",2
|
||||
if(tTmp.txt!="")
|
||||
{
|
||||
tIcon1.txt=tTmp.txt
|
||||
}
|
||||
//spstr strCommand.txt,tIcon1.txt,"~",2
|
||||
vis tIcon1,1
|
||||
// change icon color
|
||||
|
||||
@@ -1794,10 +1794,6 @@ Timer tmSerial
|
||||
{
|
||||
page cardChart
|
||||
}
|
||||
if(tId.txt=="cardLChart")
|
||||
{
|
||||
page cardLChart
|
||||
}
|
||||
}
|
||||
if(tInstruction.txt=="timeout")
|
||||
{
|
||||
|
||||
@@ -457,11 +457,6 @@ Timer tmSerial
|
||||
if(tInstruction.txt=="entityUpdateDetail"&&entn.txt==tTmp.txt)
|
||||
{
|
||||
// change icon
|
||||
spstr strCommand.txt,tTmp.txt,"~",2
|
||||
if(tTmp.txt!="")
|
||||
{
|
||||
tIcon1.txt=tTmp.txt
|
||||
}
|
||||
//spstr strCommand.txt,tIcon1.txt,"~",2
|
||||
vis tIcon1,1
|
||||
// change icon color
|
||||
|
||||
@@ -956,10 +956,6 @@ Timer tmSerial
|
||||
{
|
||||
page cardChart
|
||||
}
|
||||
if(tId.txt=="cardLChart")
|
||||
{
|
||||
page cardLChart
|
||||
}
|
||||
}
|
||||
if(tInstruction.txt=="timeout")
|
||||
{
|
||||
|
||||
BIN
HMI/nspanel.HMI
BIN
HMI/nspanel.HMI
Binary file not shown.
BIN
HMI/nspanel.tft
BIN
HMI/nspanel.tft
Binary file not shown.
@@ -65,5 +65,3 @@ SmartHomeNG: https://github.com/sisamiwe/shng-nspanel-plugin
|
||||
OpenHAB: https://github.com/donoo/o2n2l
|
||||
|
||||
NodeRed: https://github.com/laluz742/node-red-contrib-nspanel-lui
|
||||
|
||||
ESPHome without any Backend: https://github.com/olicooper/esphome-nspanel-lovelace-native
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
ha_api = None
|
||||
mqtt_api = None
|
||||
ad_api = None
|
||||
mqtt_api = None
|
||||
@@ -132,7 +132,6 @@ class LuiBackendConfig(object):
|
||||
'sleepTrackingZones': ["not_home", "off"],
|
||||
'sleepOverride': None,
|
||||
'locale': "en_US",
|
||||
'quiet': True,
|
||||
'timeFormat': "%H:%M",
|
||||
'dateFormatBabel': "full",
|
||||
'dateAdditionalTemplate': "",
|
||||
|
||||
@@ -3,7 +3,6 @@ import datetime
|
||||
import apis
|
||||
from helper import scale, pos_to_color, rgb_dec565
|
||||
from pages import LuiPagesGen
|
||||
from luibackend.config import Card
|
||||
|
||||
class LuiController(object):
|
||||
|
||||
@@ -459,9 +458,3 @@ class LuiController(object):
|
||||
apis.ha_api.get_entity(entity_id).call_service("pause")
|
||||
if button_type == "timer-finish":
|
||||
apis.ha_api.get_entity(entity_id).call_service("finish")
|
||||
|
||||
@property
|
||||
def current_card(self) -> Card:
|
||||
"""Used to get the current card"""
|
||||
|
||||
return self._current_card
|
||||
|
||||
@@ -213,9 +213,6 @@ def get_icon_ha(entity_id, overwrite=None, stateOverwrite=None):
|
||||
entity = apis.ha_api.get_entity(entity_id)
|
||||
state = entity.state if stateOverwrite is None else stateOverwrite
|
||||
|
||||
if entity_id in ["sensor.weather_forecast_daily", "sensor.weather_forecast_hourly"]:
|
||||
ha_type = "weather"
|
||||
|
||||
if overwrite is not None:
|
||||
if type(overwrite) is str:
|
||||
return get_icon_char(overwrite)
|
||||
|
||||
@@ -77,13 +77,12 @@ class LuiMqttListener(object):
|
||||
self._controller.detail_open(msg[2], msg[3])
|
||||
|
||||
class LuiMqttSender(object):
|
||||
def __init__(self, api, use_api, topic_send, api_panel_name, quiet):
|
||||
def __init__(self, api, use_api, topic_send, api_panel_name):
|
||||
self._ha_api = api
|
||||
self._use_api = use_api
|
||||
self._topic_send = topic_send
|
||||
self._api_panel_name = api_panel_name
|
||||
self._prev_msg = ""
|
||||
self._quiet = quiet
|
||||
|
||||
def send_mqtt_msg(self, msg, topic=None, force=False):
|
||||
if not force and self._prev_msg == msg:
|
||||
@@ -91,9 +90,7 @@ class LuiMqttSender(object):
|
||||
return
|
||||
self._prev_msg = msg
|
||||
|
||||
if self._quiet is False:
|
||||
apis.ha_api.log(f"Sending Message: {msg}")
|
||||
|
||||
apis.ha_api.log(f"Sending Message: {msg}")
|
||||
if self._use_api:
|
||||
apis.ha_api.call_service(service="esphome/" + self._api_panel_name + "_nspanelui_api_call", command=2, data=msg)
|
||||
else:
|
||||
|
||||
@@ -192,9 +192,6 @@ class LuiPagesGen(object):
|
||||
else:
|
||||
entityType = "delete"
|
||||
|
||||
if entityId in ["sensor.weather_forecast_daily", "sensor.weather_forecast_hourly"]:
|
||||
entityType = "weather"
|
||||
|
||||
apis.ha_api.log(f"Generating item for {entityId} with type {entityType}", level="DEBUG")
|
||||
|
||||
status_entity = apis.ha_api.get_entity(item.status) if item.status and apis.ha_api.entity_exists(item.status) else None
|
||||
@@ -224,7 +221,7 @@ class LuiPagesGen(object):
|
||||
if status_entity:
|
||||
icon_res = get_icon_ha(item.status, overwrite=icon)
|
||||
icon_color = self.get_entity_color(status_entity, ha_type=item.status.split(".")[0], overwrite=colorOverride)
|
||||
if item.status.startswith("sensor") and cardType in ["cardGrid", "cardGrid1", "cardGrid2"] and item.iconOverride is None:
|
||||
if item.status.startswith("sensor") and (cardType == "cardGrid" or cardType == "cardGrid2") and item.iconOverride is None:
|
||||
icon_res = status_entity.state[:4]
|
||||
if icon_res[-1] == ".":
|
||||
icon_res = icon_res[:-1]
|
||||
@@ -248,7 +245,7 @@ class LuiPagesGen(object):
|
||||
if status_entity:
|
||||
icon_id = get_icon_ha(item.status, overwrite=icon)
|
||||
icon_color = self.get_entity_color(status_entity, ha_type=item.status.split(".")[0], overwrite=colorOverride)
|
||||
if item.status.startswith("sensor") and cardType in ["cardGrid", "cardGrid1", "cardGrid2"] and item.iconOverride is None:
|
||||
if item.status.startswith("sensor") and (cardType == "cardGrid" or cardType == "cardGrid2") and item.iconOverride is None:
|
||||
icon_id = status_entity.state[:4]
|
||||
if icon_id[-1] == ".":
|
||||
icon_id = icon_id[:-1]
|
||||
@@ -321,7 +318,7 @@ class LuiPagesGen(object):
|
||||
value = value + unit_of_measurement
|
||||
if entityType == "binary_sensor":
|
||||
value = get_translation(self._locale, f"backend.component.binary_sensor.state.{device_class}.{entity.state}")
|
||||
if cardType in ["cardGrid", "cardGrid1", "cardGrid2"] and entityType == "sensor" and icon is None:
|
||||
if (cardType == "cardGrid" or cardType == "cardGrid2") and entityType == "sensor" and icon is None:
|
||||
icon_id = entity.state[:4]
|
||||
if icon_id[-1] == ".":
|
||||
icon_id = icon_id[:-1]
|
||||
@@ -782,8 +779,6 @@ class LuiPagesGen(object):
|
||||
if send_page_type:
|
||||
if card.cardType == "cardGrid" and len(card.entities) > 6:
|
||||
card.cardType = "cardGrid2"
|
||||
if card.cardType == "cardGrid1":
|
||||
card.cardType = "cardGrid"
|
||||
self.page_type(card.cardType)
|
||||
|
||||
# send sleep timeout if there is one configured for the current card
|
||||
@@ -793,7 +788,7 @@ class LuiPagesGen(object):
|
||||
self._send_mqtt_msg(f'timeout~{self._config.get("sleepTimeout")}')
|
||||
|
||||
temp_unit = card.raw_config.get("temperatureUnit", "celsius")
|
||||
if card.cardType in ["cardEntities", "cardGrid", "cardGrid1","cardGrid2"]:
|
||||
if card.cardType in ["cardEntities", "cardGrid", "cardGrid2"]:
|
||||
self.generate_entities_page(navigation, card.title, card.entities, card.cardType, temp_unit)
|
||||
return
|
||||
if card.cardType == "cardThermo":
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import adbase as ad
|
||||
import hassapi as hass
|
||||
|
||||
from luibackend.config import LuiBackendConfig
|
||||
from luibackend.controller import LuiController
|
||||
@@ -6,19 +6,15 @@ from luibackend.mqtt import LuiMqttListener, LuiMqttSender
|
||||
from luibackend.updater import Updater
|
||||
|
||||
import apis
|
||||
import json
|
||||
from typing import Literal
|
||||
|
||||
class NsPanelLovelaceUIManager(ad.ADBase):
|
||||
class NsPanelLovelaceUIManager(hass.Hass):
|
||||
|
||||
def initialize(self):
|
||||
self.adapi = self.get_ad_api()
|
||||
self.adapi.log('Starting')
|
||||
apis.ad_api = self.adapi
|
||||
apis.ha_api = self.get_plugin_api("HASS")
|
||||
self.log('Starting')
|
||||
apis.ha_api = self
|
||||
apis.mqtt_api = self.get_plugin_api("MQTT")
|
||||
|
||||
cfg = self._cfg = LuiBackendConfig(apis.ha_api, self.args["config"])
|
||||
cfg = self._cfg = LuiBackendConfig(self, self.args["config"])
|
||||
|
||||
use_api = cfg.get("use_api") == True
|
||||
|
||||
@@ -26,11 +22,10 @@ class NsPanelLovelaceUIManager(ad.ADBase):
|
||||
topic_recv = cfg.get("panelRecvTopic")
|
||||
api_panel_name = cfg.get("panelName")
|
||||
api_device_id = cfg.get("panelDeviceId")
|
||||
quiet = cfg.get("quiet")
|
||||
|
||||
mqttsender = self._mqttsender = LuiMqttSender(apis.ha_api, use_api, topic_send, api_panel_name, quiet)
|
||||
mqttsend = LuiMqttSender(self, use_api, topic_send, api_panel_name)
|
||||
|
||||
self._controller = LuiController(cfg, mqttsender.send_mqtt_msg)
|
||||
controller = LuiController(cfg, mqttsend.send_mqtt_msg)
|
||||
|
||||
desired_tasmota_driver_version = 8
|
||||
desired_display_firmware_version = 53
|
||||
@@ -46,35 +41,11 @@ class NsPanelLovelaceUIManager(ad.ADBase):
|
||||
desired_tasmota_driver_url = cfg._config.get("berryURL", "https://raw.githubusercontent.com/joBr99/nspanel-lovelace-ui/main/tasmota/autoexec.be")
|
||||
|
||||
mode = cfg.get("updateMode")
|
||||
updater = Updater(self.adapi.log, mqttsender, topic_send, mode, desired_display_firmware_version, model, desired_display_firmware_url, desired_tasmota_driver_version, desired_tasmota_driver_url)
|
||||
updater = Updater(self.log, mqttsend, topic_send, mode, desired_display_firmware_version, model, desired_display_firmware_url, desired_tasmota_driver_version, desired_tasmota_driver_url)
|
||||
|
||||
# Request Tasmota Driver Version
|
||||
updater.request_berry_driver_version()
|
||||
|
||||
LuiMqttListener(use_api, topic_recv, api_panel_name, api_device_id, self._controller, updater)
|
||||
LuiMqttListener(use_api, topic_recv, api_panel_name, api_device_id, controller, updater)
|
||||
|
||||
self.adapi.log(f'Started ({version})')
|
||||
|
||||
#
|
||||
# helpers
|
||||
#
|
||||
|
||||
def show_card(self, card_key: str) -> None:
|
||||
"""Used to show card on panel"""
|
||||
|
||||
msg = json.dumps({"CustomRecv":f"event,buttonPress2,navigate.{card_key},button"})
|
||||
topic = self._cfg.get("panelRecvTopic")
|
||||
self._mqttsender.send_mqtt_msg(msg, topic)
|
||||
|
||||
def navigate(self, direction: Literal['up', 'prev', 'next']) -> None:
|
||||
"""Used to navigate different directions on the panel"""
|
||||
|
||||
msg = json.dumps({"CustomRecv":f"event,buttonPress2,nav{direction.title()},button"})
|
||||
topic = self._cfg.get("panelRecvTopic")
|
||||
self._mqttsender.send_mqtt_msg(msg, topic)
|
||||
|
||||
@property
|
||||
def current_card(self) -> str:
|
||||
"""Used to get the panel's current card"""
|
||||
|
||||
return self._controller.current_card.key
|
||||
self.log(f'Started ({version})')
|
||||
|
||||
@@ -44,6 +44,8 @@ Using a 6th entity will automatically activate the alternative layout.
|
||||
type: 0
|
||||
- entity: weather.demo_weather_north
|
||||
type: 1
|
||||
- entity: weather.demo_weather_north
|
||||
type: 2
|
||||
- entity: sensor.energy_usage
|
||||
- entity: delete
|
||||
- entity: sensor.indoor_temp
|
||||
|
||||
@@ -93,34 +93,3 @@ Now, to install NSPanel Lovelace UI Backend with HACS, follow these steps:
|
||||
6. A confirmation panel will appear, click on `Download`, and wait for HACS to
|
||||
proceed with the download
|
||||
7. The Backend Application is now installed, and HACS will inform you when updates are available
|
||||
|
||||
# Workaround for HomeAssistant 2024.04
|
||||
AppDaemon is using the old REST API that until AppDaemon moved on the the websocket API this woraround is needed to get weather forecast data from homeassistant. (https://github.com/AppDaemon/appdaemon/issues/1837)
|
||||
|
||||
To get the forecast data in appdaemon, there is a script needed in homeassistant's configuration.yaml:
|
||||
|
||||
```yaml
|
||||
template:
|
||||
- trigger:
|
||||
- platform: time_pattern
|
||||
hours: /1
|
||||
action:
|
||||
- service: weather.get_forecasts
|
||||
data:
|
||||
type: daily
|
||||
target:
|
||||
entity_id: weather.k3ll3r # change to your weather entity in this line
|
||||
response_variable: daily
|
||||
sensor:
|
||||
- name: Weather Forecast Daily
|
||||
unique_id: weather_forecast_daily
|
||||
state: "{{ now().isoformat() }}"
|
||||
attributes:
|
||||
forecast: "{{ daily['weather.k3ll3r'].forecast }}" # change to your weather entity in this line
|
||||
```
|
||||

|
||||
|
||||
Adjust the entities in your apps.yaml that are accessing the forecast to the newly created trigger template:
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*-----------------------------------------------------------------------
|
||||
TypeScript v4.3.3.43 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne
|
||||
TypeScript v4.3.3.42 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne
|
||||
- abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.0
|
||||
@joBr99 Projekt: https://github.com/joBr99/nspanel-lovelace-ui/tree/main/ioBroker
|
||||
NsPanelTs.ts (dieses TypeScript in ioBroker) Stable: https://github.com/joBr99/nspanel-lovelace-ui/blob/main/ioBroker/NsPanelTs.ts
|
||||
@@ -112,11 +112,9 @@ ReleaseNotes:
|
||||
- 06.02.2024 - v4.3.3.41 Fix: activeBrightness -> null
|
||||
- 06.02.2024 - v4.3.3.41 Fix: bHome -> corrected PageId
|
||||
- 07.02.2024 - v4.3.3.42 Minor Fixes
|
||||
- 09.02.2024 - v4.3.3.42 Change pageId with Alias in Communication with HMI
|
||||
- 09.02.2024 - v4.3.3.42 Spotify Media-Player: Dynamic loading of the speaker list, playlist, tracklist, fix repeat, add seek, add elapsed/duration
|
||||
- 10.02.2024 - v4.3.3.42 Spotify Minor Fixes; Add miValue / maxValue to Volume-Slider
|
||||
- 10.02.2024 - v4.3.3.43 Fix: cardGrid2 => 9 Entities for Layout 'us-p' issue #1167
|
||||
- 11.02.2024 - v4.3.3.43 Fix VolumeSlider
|
||||
- 09.02.2024 - v4.3.3.42 Change pageId with Alias in Communication with HMI (cardMedia)
|
||||
- 09.02.2024 - v4.3.3.42 spotiffy Media-Player: Dynamic loading of the speaker list, playlist, tracklist, fix repeat, add seek, add elapsed/duration
|
||||
|
||||
|
||||
Todo:
|
||||
- XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined
|
||||
@@ -138,8 +136,7 @@ Mögliche Seiten-Ansichten:
|
||||
(die 4 kleineren Icons können als Wetter-Vorschau + 4Tage (Symbol + Höchsttemperatur) oder zur Anzeige definierter Infos konfiguriert werden)
|
||||
cardEntities Page - 4 vertikale angeordnete Steuerelemente - auch als Subpage
|
||||
cardGrid Page - 6 horizontal angeordnete Steuerelemente in 2 Reihen a 3 Steuerelemente - auch als Subpage
|
||||
cardGrid2 Page - 8 horizontal angeordnete Steuerelemente in 2 Reihen a 4 Steuerelemente bzw. beim US-Modell im Portrait-Modus
|
||||
9 horizontal angeordnete Steuerelemente in 3 Reihen a 3 Steuerelemente - auch als Subpage
|
||||
cardGrid2 Page - 8 horizontal angeordnete Steuerelemente in 2 Reihen a 4 Steuerelemente - auch als Subpage
|
||||
cardThermo Page - Thermostat mit Solltemperatur, Isttemperatur, Mode - Weitere Eigenschaften können im Alias definiert werden
|
||||
cardMedia Page - Mediaplayer - Ausnahme: Alias sollte mit Alias-Manager automatisch über Alexa-Verzeichnis Player angelegt werden
|
||||
cardAlarm Page - Alarmseite mit Zustand und Tastenfeld
|
||||
@@ -215,7 +212,6 @@ Upgrades in Konsole:
|
||||
---------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/******************************* Begin CONFIG Parameter *******************************/
|
||||
|
||||
// DE: liefert bei true detailliertere Meldundgen im Log.
|
||||
@@ -985,7 +981,7 @@ export const config: Config = {
|
||||
// _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________
|
||||
// _________________________________ EN: No more configuration from here _____________________________________
|
||||
|
||||
const scriptVersion: string = 'v4.3.3.43';
|
||||
const scriptVersion: string = 'v4.3.3.42';
|
||||
const tft_version: string = 'v4.3.3';
|
||||
const desired_display_firmware_version = 53;
|
||||
const berry_driver_version = 9;
|
||||
@@ -3386,11 +3382,7 @@ function GeneratePageElements(page: PageType): string {
|
||||
maxItems = 6;
|
||||
break;
|
||||
case 'cardGrid2':
|
||||
if (getState(NSPanel_Path + 'NSPanel_Version').val == 'us-p') {
|
||||
maxItems = 9;
|
||||
} else {
|
||||
maxItems = 8;
|
||||
};
|
||||
maxItems = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4769,25 +4761,97 @@ function unsubscribeMediaSubscriptions(): void {
|
||||
|
||||
function subscribeMediaSubscriptions(id: string): void {
|
||||
on({id: [id + '.STATE',
|
||||
id + '.ARTIST',
|
||||
id + '.TITLE',
|
||||
id + '.ALBUM',
|
||||
id + '.VOLUME',
|
||||
id + '.ARTIST',
|
||||
id + '.ALBUM',
|
||||
id + '.TITLE',
|
||||
id + '.REPEAT',
|
||||
id + '.SHUFFLE',
|
||||
id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any", ack: true}, async function () {
|
||||
if (useMediaEvents && pageCounter == 1) {
|
||||
GeneratePage(activePage!);
|
||||
}
|
||||
id + '.SHUFFLE'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 3000);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsSonosAdd(id: string): void {
|
||||
on({id: [id + '.QUEUE'], change: "any", ack: true}, async function () {
|
||||
if (useMediaEvents && pageCounter == 1) {
|
||||
GeneratePage(activePage!);
|
||||
}
|
||||
on({id: [id + '.QUEUE',
|
||||
id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsAlexaAdd(id: string): void {
|
||||
on({id: [id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsBoseAdd(id: string): void {
|
||||
on({id: [id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsSqueezeboxAdd(id: string): void {
|
||||
on({id: [id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsSpotifyAdd(id: string): void {
|
||||
on({id: [id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5088,7 +5152,14 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
subscribeMediaSubscriptions(page.items[0].id);
|
||||
if (v2Adapter == 'sonos') {
|
||||
subscribeMediaSubscriptionsSonosAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'alexa2') {
|
||||
subscribeMediaSubscriptionsAlexaAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'bosesoundtouch') {
|
||||
subscribeMediaSubscriptionsBoseAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'squeezeboxrpc') {
|
||||
subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'spotify-premium') {
|
||||
subscribeMediaSubscriptionsSpotifyAdd(page.items[0].id);
|
||||
setState(vInstance + 'getDevices', true);
|
||||
setState(vInstance + 'getPlaybackInfo', true);
|
||||
setState(vInstance + 'getPlaylists', true);
|
||||
@@ -5100,7 +5171,15 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
alwaysOn = true;
|
||||
subscribeMediaSubscriptions(page.items[0].id);
|
||||
if (v2Adapter == 'sonos') {
|
||||
subscribeMediaSubscriptionsSonosAdd(page.items[0].id);
|
||||
subscribeMediaSubscriptionsSonosAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'alexa2') {
|
||||
subscribeMediaSubscriptionsAlexaAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'bosesoundtouch') {
|
||||
subscribeMediaSubscriptionsBoseAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'squeezeboxrpc') {
|
||||
subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'spotify-premium') {
|
||||
subscribeMediaSubscriptionsSpotifyAdd(page.items[0].id);
|
||||
}
|
||||
} else if (page.type == 'cardMedia' && pageCounter == -1) {
|
||||
//Do Nothing
|
||||
@@ -5225,16 +5304,12 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
media_icon = Icons.GetIcon('spotify');
|
||||
name = getState(id + '.CONTEXT_DESCRIPTION').val;
|
||||
let nameLength = name.length;
|
||||
if (name.substring(0,17) == 'Playlist: This Is') {
|
||||
name = name.slice(18, 34) + '...';
|
||||
} else if (name.substring(0,9) == 'Playlist:') {
|
||||
if (name.substring(0,9) == 'Playlist:') {
|
||||
name = name.slice(10, 26) + '...';
|
||||
} else if (name.substring(0,6) == 'Album:') {
|
||||
name = name.slice(7, 23) + '...';
|
||||
} else if (name.substring(0,6) == 'Track:') {
|
||||
name = name.slice(7, 23) + '...';
|
||||
} else if (name.substring(0,7) == 'Artist:') {
|
||||
name = name.slice(8, 24) + '...';
|
||||
} else if (name.substring(0,6) == 'Track') {
|
||||
name = 'Spotify-Premium';
|
||||
}
|
||||
if (nameLength == 0) {
|
||||
name = 'Spotify-Premium';
|
||||
@@ -5332,7 +5407,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
name = page.heading;
|
||||
}
|
||||
|
||||
let volume = scale(getState(id + '.VOLUME').val, activePage!.items[0]!.minValue ?? 0, activePage!.items[0]!.maxValue ?? 100, 100, 0);
|
||||
let volume = getState(id + '.VOLUME').val;
|
||||
let iconplaypause = Icons.GetIcon('pause'); //pause
|
||||
let shuffle_icon = Icons.GetIcon('shuffle-variant'); //shuffle
|
||||
let onoffbutton = 1374;
|
||||
@@ -5539,7 +5614,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
let tempTrackList = JSON.parse(getState(page.items[0].adapterPlayerInstance + 'player.playlist.trackListArray').val);
|
||||
globalTracklist = tempTrackList;
|
||||
} catch {
|
||||
log('Hello Mr. Developer something went wrong in tracklist!', 'debug')
|
||||
log('Hello Mr. Developer something went wrong in tracklist!', 'warn')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5617,6 +5692,11 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
repeatIcon = Icons.GetIcon('repeat');
|
||||
repeatIconCol = rgb_dec565(HMIOn);
|
||||
}
|
||||
/*
|
||||
else {
|
||||
repeatIcon = Icons.GetIcon('repeat-off');
|
||||
}
|
||||
*/
|
||||
} else if (v2Adapter == 'volumio') { /* Volumio: only Repeat true/false with API */
|
||||
if (getState(id + '.REPEAT').val == true) {
|
||||
repeatIcon = Icons.GetIcon('repeat-variant');
|
||||
@@ -5708,6 +5788,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if (Debug) {
|
||||
log('GenerateMediaPage payload: ' + JSON.stringify(out_msgs), 'info');
|
||||
}
|
||||
if (Debug) log(JSON.stringify(out_msgs).length);
|
||||
if (Debug) log('GenerateMediaPage payload: ' + JSON.stringify(out_msgs), 'info');
|
||||
return out_msgs
|
||||
} catch (err: any) {
|
||||
log('error at function GenerateMediaPage: ' + err.message, 'warn');
|
||||
@@ -6107,6 +6189,8 @@ function subscribePowerSubscriptions(id: string): void {
|
||||
function GeneratePowerPage(page: NSPanel.PagePower): NSPanel.Payload[] {
|
||||
try {
|
||||
|
||||
if (!page.items[0].id) throw new Error ('Missing pageItem.id for PowerPage!');
|
||||
|
||||
let obj:object = {};
|
||||
let demoMode = false;
|
||||
if (page.items[0].id == undefined){
|
||||
@@ -6633,8 +6717,8 @@ function HandleButtonEvent(words: any): void {
|
||||
|
||||
switch (deviceAdapterRP) {
|
||||
case 'spotify-premium':
|
||||
if (Debug) log(getState(id + '.REPEAT').val);
|
||||
let stateSpotifyRepeat = getState(id + '.REPEAT').val;
|
||||
log(getState(id + '.REPEAT').val)
|
||||
let stateSpotifyRepeat = getState(id + '.REPEAT').val
|
||||
if (stateSpotifyRepeat == 'off') {
|
||||
setIfExists(id + '.REPEAT', 'context');
|
||||
} else if (stateSpotifyRepeat == 'context') {
|
||||
@@ -6646,7 +6730,7 @@ function HandleButtonEvent(words: any): void {
|
||||
break;
|
||||
case 'bosesoundtouch':
|
||||
if (Debug) log(adapterInstanceRepeat);
|
||||
let stateBoseRepeat = getState(id + '.REPEAT').val;
|
||||
let stateBoseRepeat = getState(id + '.REPEAT').val
|
||||
if (stateBoseRepeat == 'REPEAT_OFF') {
|
||||
setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ALL');
|
||||
} else if (stateBoseRepeat == 'REPEAT_ALL') {
|
||||
@@ -6657,7 +6741,7 @@ function HandleButtonEvent(words: any): void {
|
||||
GeneratePage(activePage!);
|
||||
break;
|
||||
case 'sonos':
|
||||
let stateSonosRepeat = getState(id + '.REPEAT').val;
|
||||
let stateSonosRepeat = getState(id + '.REPEAT').val
|
||||
if (stateSonosRepeat == 0) {
|
||||
setIfExists(id + '.REPEAT', 1);
|
||||
} else if (stateSonosRepeat == 1) {
|
||||
@@ -6956,11 +7040,15 @@ function HandleButtonEvent(words: any): void {
|
||||
break;
|
||||
}
|
||||
case 'volumeSlider':
|
||||
subscribeMediaSubscriptions(id);
|
||||
useMediaEvents = true;
|
||||
pageCounter = 1;
|
||||
let vVolume = scale(parseInt(words[4]), 100, 0, activePage!.items[0]!.minValue ?? 0, activePage!.items[0]!.maxValue ?? 100);
|
||||
setIfExists(id + '.VOLUME', Math.floor(vVolume));
|
||||
pageCounter = -1;
|
||||
(function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })();
|
||||
timeoutSlider = setTimeout(async function () {
|
||||
setIfExists(id + '.VOLUME', parseInt(words[4]));
|
||||
setTimeout(async function () {
|
||||
pageCounter = 1;
|
||||
GeneratePage(activePage!);
|
||||
}, 3000);
|
||||
}, 20);
|
||||
break;
|
||||
case 'mode-speakerlist':
|
||||
let pageItem = findPageItem(id);
|
||||
@@ -8982,8 +9070,6 @@ function HandleScreensaverUpdate(): void {
|
||||
SendToPanel({ payload: 'weatherUpdate~' + payloadString });
|
||||
|
||||
HandleScreensaverStatusIcons();
|
||||
|
||||
HandleScreensaverColors();
|
||||
}
|
||||
|
||||
} catch (err: any) {
|
||||
@@ -9978,7 +10064,7 @@ namespace NSPanel {
|
||||
export type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan'
|
||||
|
||||
export type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'ct' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume'
|
||||
| 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning'
|
||||
| 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct'
|
||||
| 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider'
|
||||
| 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition'
|
||||
|
||||
@@ -10038,7 +10124,7 @@ namespace NSPanel {
|
||||
|
||||
export type PageGrid2 = {
|
||||
type: 'cardGrid2',
|
||||
items: [PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?],
|
||||
items: [PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?],
|
||||
} & PageBaseType
|
||||
|
||||
export type PageThermo = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*-----------------------------------------------------------------------
|
||||
TypeScript v4.3.3.43 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne
|
||||
TypeScript v4.3.3.41 zur Steuerung des SONOFF NSPanel mit dem ioBroker by @Armilar / @TT-Tom / @ticaki / @Britzelpuf / @Sternmiere / @ravenS0ne
|
||||
- abgestimmt auf TFT 53 / v4.3.3 / BerryDriver 9 / Tasmota 13.3.0
|
||||
@joBr99 Projekt: https://github.com/joBr99/nspanel-lovelace-ui/tree/main/ioBroker
|
||||
NsPanelTs.ts (dieses TypeScript in ioBroker) Stable: https://github.com/joBr99/nspanel-lovelace-ui/blob/main/ioBroker/NsPanelTs.ts
|
||||
@@ -111,12 +111,7 @@ ReleaseNotes:
|
||||
- 05.02.2024 - v4.3.3.40 Fix: SqueezeboxRPC-Media-Player and add some Functions
|
||||
- 06.02.2024 - v4.3.3.41 Fix: activeBrightness -> null
|
||||
- 06.02.2024 - v4.3.3.41 Fix: bHome -> corrected PageId
|
||||
- 07.02.2024 - v4.3.3.42 Minor Fixes
|
||||
- 09.02.2024 - v4.3.3.42 Change pageId with Alias in Communication with HMI
|
||||
- 09.02.2024 - v4.3.3.42 Spotify Media-Player: Dynamic loading of the speaker list, playlist, tracklist, fix repeat, add seek, add elapsed/duration
|
||||
- 10.02.2024 - v4.3.3.42 Spotify Minor Fixes; Add miValue / maxValue to Volume-Slider
|
||||
- 10.02.2024 - v4.3.3.43 Fix: cardGrid2 => 9 Entities for Layout 'us-p' issue #1167
|
||||
- 11.02.2024 - v4.3.3.43 Fix VolumeSlider
|
||||
|
||||
|
||||
Todo:
|
||||
- XX.XX.XXXX - v5.0.0 Change the bottomScreensaverEntity (rolling) if more than 6 entries are defined
|
||||
@@ -138,8 +133,7 @@ Mögliche Seiten-Ansichten:
|
||||
(die 4 kleineren Icons können als Wetter-Vorschau + 4Tage (Symbol + Höchsttemperatur) oder zur Anzeige definierter Infos konfiguriert werden)
|
||||
cardEntities Page - 4 vertikale angeordnete Steuerelemente - auch als Subpage
|
||||
cardGrid Page - 6 horizontal angeordnete Steuerelemente in 2 Reihen a 3 Steuerelemente - auch als Subpage
|
||||
cardGrid2 Page - 8 horizontal angeordnete Steuerelemente in 2 Reihen a 4 Steuerelemente bzw. beim US-Modell im Portrait-Modus
|
||||
9 horizontal angeordnete Steuerelemente in 3 Reihen a 3 Steuerelemente - auch als Subpage
|
||||
cardGrid2 Page - 8 horizontal angeordnete Steuerelemente in 2 Reihen a 4 Steuerelemente - auch als Subpage
|
||||
cardThermo Page - Thermostat mit Solltemperatur, Isttemperatur, Mode - Weitere Eigenschaften können im Alias definiert werden
|
||||
cardMedia Page - Mediaplayer - Ausnahme: Alias sollte mit Alias-Manager automatisch über Alexa-Verzeichnis Player angelegt werden
|
||||
cardAlarm Page - Alarmseite mit Zustand und Tastenfeld
|
||||
@@ -215,7 +209,6 @@ Upgrades in Konsole:
|
||||
---------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/******************************* Begin CONFIG Parameter *******************************/
|
||||
|
||||
// DE: liefert bei true detailliertere Meldundgen im Log.
|
||||
@@ -985,7 +978,7 @@ export const config: Config = {
|
||||
// _________________________________ DE: Ab hier keine Konfiguration mehr _____________________________________
|
||||
// _________________________________ EN: No more configuration from here _____________________________________
|
||||
|
||||
const scriptVersion: string = 'v4.3.3.43';
|
||||
const scriptVersion: string = 'v4.3.3.41';
|
||||
const tft_version: string = 'v4.3.3';
|
||||
const desired_display_firmware_version = 53;
|
||||
const berry_driver_version = 9;
|
||||
@@ -3386,11 +3379,7 @@ function GeneratePageElements(page: PageType): string {
|
||||
maxItems = 6;
|
||||
break;
|
||||
case 'cardGrid2':
|
||||
if (getState(NSPanel_Path + 'NSPanel_Version').val == 'us-p') {
|
||||
maxItems = 9;
|
||||
} else {
|
||||
maxItems = 8;
|
||||
};
|
||||
maxItems = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4769,25 +4758,81 @@ function unsubscribeMediaSubscriptions(): void {
|
||||
|
||||
function subscribeMediaSubscriptions(id: string): void {
|
||||
on({id: [id + '.STATE',
|
||||
id + '.ARTIST',
|
||||
id + '.TITLE',
|
||||
id + '.ALBUM',
|
||||
id + '.VOLUME',
|
||||
id + '.ARTIST',
|
||||
id + '.ALBUM',
|
||||
id + '.TITLE',
|
||||
id + '.REPEAT',
|
||||
id + '.SHUFFLE',
|
||||
id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any", ack: true}, async function () {
|
||||
if (useMediaEvents && pageCounter == 1) {
|
||||
GeneratePage(activePage!);
|
||||
}
|
||||
id + '.SHUFFLE'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 3000);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsSonosAdd(id: string): void {
|
||||
on({id: [id + '.QUEUE'], change: "any", ack: true}, async function () {
|
||||
if (useMediaEvents && pageCounter == 1) {
|
||||
GeneratePage(activePage!);
|
||||
}
|
||||
on({id: [id + '.QUEUE',
|
||||
id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsAlexaAdd(id: string): void {
|
||||
on({id: [id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsBoseAdd(id: string): void {
|
||||
on({id: [id + '.DURATION',
|
||||
id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
function subscribeMediaSubscriptionsSqueezeboxAdd(id: string): void {
|
||||
on({id: [id + '.ELAPSED'], change: "any"}, async function () {
|
||||
(function () { if (timeoutMedia) { clearTimeout(timeoutMedia); timeoutMedia = null; } })();
|
||||
timeoutMedia = setTimeout(async function () {
|
||||
if (useMediaEvents) {
|
||||
GeneratePage(activePage!);
|
||||
setTimeout(async function () {
|
||||
GeneratePage(activePage!);
|
||||
}, 50);
|
||||
}
|
||||
},50)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4916,13 +4961,6 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla
|
||||
log('error at function createAutoMediaAlias Adapter spotify-premium: ' + err.message, 'warn');
|
||||
}
|
||||
}
|
||||
//Add Spotify Datapoints > v4.3.3.42
|
||||
//Spotify-Premium has Role value and a known Bug in player.progress
|
||||
if (existsObject(id + '.DURATION') == false) {
|
||||
const dpPath: string = adapterPlayerInstance;
|
||||
await createAliasAsync(id + '.DURATION', dpPath + 'player.duration', true, <iobJS.StateCommon> {type: 'string', role: 'media.duration.text', name: 'DURATION'});
|
||||
await createAliasAsync(id + '.ELAPSED', dpPath + 'player.progress', true, <iobJS.StateCommon> {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'});
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
@@ -4960,12 +4998,7 @@ async function createAutoMediaAlias (id: string, mediaDevice: string, adapterPla
|
||||
log('error function createAutoMediaAlias Adapter volumio: ' + err.message, 'warn');
|
||||
}
|
||||
}
|
||||
//Add Volumio Datapoints > v4.3.3.42
|
||||
if (existsObject(id + '.DURATION') == false) {
|
||||
const dpPath: string = adapterPlayerInstance;
|
||||
await createAliasAsync(id + '.DURATION', dpPath + 'playbackInfo.duration', true, <iobJS.StateCommon> {type: 'string', role: 'media.duration', name: 'DURATION'});
|
||||
//await createAliasAsync(id + '.ELAPSED', dpPath + 'player.progress', true, <iobJS.StateCommon> {type: 'string', role: 'media.elapsed.text', name: 'ELAPSED'});
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case "squeezeboxrpc.0.":
|
||||
@@ -5061,7 +5094,6 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if (!page.items[0].id) throw new Error ('Missing page id for cardMedia!');
|
||||
|
||||
let id = page.items[0].id;
|
||||
let tid = 0;
|
||||
let out_msgs: NSPanel.Payload[] = [];
|
||||
|
||||
if (!page.items[0].adapterPlayerInstance!) throw new Error('page.items[0].adapterPlayerInstance is undefined!')
|
||||
@@ -5088,10 +5120,12 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
subscribeMediaSubscriptions(page.items[0].id);
|
||||
if (v2Adapter == 'sonos') {
|
||||
subscribeMediaSubscriptionsSonosAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'spotify-premium') {
|
||||
setState(vInstance + 'getDevices', true);
|
||||
setState(vInstance + 'getPlaybackInfo', true);
|
||||
setState(vInstance + 'getPlaylists', true);
|
||||
} else if (v2Adapter == 'alexa2') {
|
||||
subscribeMediaSubscriptionsAlexaAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'bosesoundtouch') {
|
||||
subscribeMediaSubscriptionsBoseAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'squeezeboxrpc') {
|
||||
subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5100,7 +5134,13 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
alwaysOn = true;
|
||||
subscribeMediaSubscriptions(page.items[0].id);
|
||||
if (v2Adapter == 'sonos') {
|
||||
subscribeMediaSubscriptionsSonosAdd(page.items[0].id);
|
||||
subscribeMediaSubscriptionsSonosAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'alexa2') {
|
||||
subscribeMediaSubscriptionsAlexaAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'bosesoundtouch') {
|
||||
subscribeMediaSubscriptionsBoseAdd(page.items[0].id);
|
||||
} else if (v2Adapter == 'squeezeboxrpc') {
|
||||
subscribeMediaSubscriptionsSqueezeboxAdd(page.items[0].id);
|
||||
}
|
||||
} else if (page.type == 'cardMedia' && pageCounter == -1) {
|
||||
//Do Nothing
|
||||
@@ -5111,8 +5151,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if (existsObject(id)) {
|
||||
let name = getState(id + '.ALBUM').val;
|
||||
let title = getState(id + '.TITLE').val;
|
||||
if (title.length > 26) {
|
||||
title = title.slice(0, 26) + '...';
|
||||
if (title.length > 27) {
|
||||
title = title.slice(0, 27) + '...';
|
||||
}
|
||||
if (existsObject(id + '.DURATION') && existsObject(id + '.ELAPSED')) {
|
||||
if (v2Adapter == 'alexa2') {
|
||||
@@ -5133,15 +5173,8 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if(parseInt(vDuration.slice(0,2)) < 9) {
|
||||
vDuration = vDuration.slice(1);
|
||||
}
|
||||
}
|
||||
if (vDuration != '0:00') {
|
||||
title = title + ' (' + vElapsed + '|' + vDuration + ')';
|
||||
} else {
|
||||
title = title + ' (' + vElapsed + ')';
|
||||
}
|
||||
if (title == ' (0:00)') {
|
||||
title = '';
|
||||
}
|
||||
}
|
||||
title = title + ' (' + vElapsed + '|' + vDuration + ')';
|
||||
} else if (v2Adapter == 'sonos' && getState(page.items[0].adapterPlayerInstance + 'root.' + page.items[0].mediaDevice + '.current_type').val == 0) {
|
||||
let vElapsed = getState(id + '.ELAPSED').val;
|
||||
if (vElapsed.length == 5) {
|
||||
@@ -5197,24 +5230,6 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
}
|
||||
}
|
||||
|
||||
// Settings >>Aktualisierungsintervall für Statusinformationen<< = 1 !
|
||||
// If the refresh time is set to 1 second in the spotify-premium.X instance,
|
||||
// the elapsed refresh bug '00:00' is not visible
|
||||
if (v2Adapter == 'spotify-premium') {
|
||||
let vElapsed: string = getState(id + '.ELAPSED').val;
|
||||
if (vElapsed.substring(0,1) == '0') {
|
||||
vElapsed = vElapsed.slice(1)
|
||||
}
|
||||
let vDuration: string = getState(id + '.DURATION').val;
|
||||
if (vDuration.substring(0,1) == '0') {
|
||||
vDuration = vDuration.slice(1)
|
||||
}
|
||||
title = title + ' (' + vElapsed + '|' + vDuration + ')';
|
||||
if (title == ' (0:00|0:00)') {
|
||||
title = '';
|
||||
}
|
||||
}
|
||||
|
||||
let shuffle = getState(id + '.SHUFFLE').val;
|
||||
|
||||
//New Adapter/Player
|
||||
@@ -5225,23 +5240,19 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
media_icon = Icons.GetIcon('spotify');
|
||||
name = getState(id + '.CONTEXT_DESCRIPTION').val;
|
||||
let nameLength = name.length;
|
||||
if (name.substring(0,17) == 'Playlist: This Is') {
|
||||
name = name.slice(18, 34) + '...';
|
||||
} else if (name.substring(0,9) == 'Playlist:') {
|
||||
if (name.substring(0,9) == 'Playlist:') {
|
||||
name = name.slice(10, 26) + '...';
|
||||
} else if (name.substring(0,6) == 'Album:') {
|
||||
name = name.slice(7, 23) + '...';
|
||||
} else if (name.substring(0,6) == 'Track:') {
|
||||
name = name.slice(7, 23) + '...';
|
||||
} else if (name.substring(0,7) == 'Artist:') {
|
||||
name = name.slice(8, 24) + '...';
|
||||
} else if (name.substring(0,6) == 'Track') {
|
||||
name = 'Spotify-Premium';
|
||||
}
|
||||
if (nameLength == 0) {
|
||||
name = 'Spotify-Premium';
|
||||
}
|
||||
author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val;
|
||||
if (author.length > 37) {
|
||||
author = author.slice(0,37) + '...';
|
||||
if (author.length > 30) {
|
||||
author = getState(id + '.ARTIST').val;
|
||||
}
|
||||
if ((getState(id + '.ARTIST').val).length == 0) {
|
||||
author = findLocale('media','no_music_to_control');
|
||||
@@ -5292,10 +5303,9 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
//Logitech Squeezebox RPC
|
||||
if (v2Adapter == 'squeezeboxrpc') {
|
||||
media_icon = Icons.GetIcon('dlna');
|
||||
if (name.length == 0) {
|
||||
name = page.heading;
|
||||
} else if (name.length > 16) {
|
||||
name = name.slice(0,16) + '...'
|
||||
let nameLength = name.length;
|
||||
if (nameLength == 0) {
|
||||
name = page.items[0].mediaDevice;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5313,8 +5323,6 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
}
|
||||
if (nameLength == 0) {
|
||||
name = 'Alexa Player';
|
||||
} else {
|
||||
name = name.slice(0,16) + '...';
|
||||
}
|
||||
author = getState(id + '.ARTIST').val + ' | ' + getState(id + '.ALBUM').val;
|
||||
if (author.length > 30) {
|
||||
@@ -5327,12 +5335,12 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
|
||||
//Volumio
|
||||
if (v2Adapter == 'volumio') {
|
||||
media_icon = Icons.GetIcon('clock-time-twelve-outline');
|
||||
if (name != undefined) { author = author + " | " + name; }
|
||||
name = page.heading;
|
||||
if (name != undefined) { author = author + " [" + name + "]"; }
|
||||
name = getState(vInstance + 'info.name').val; /* page.heading;
|
||||
getState(id + '.TRACK').val; */
|
||||
}
|
||||
|
||||
let volume = scale(getState(id + '.VOLUME').val, activePage!.items[0]!.minValue ?? 0, activePage!.items[0]!.maxValue ?? 100, 100, 0);
|
||||
let volume = getState(id + '.VOLUME').val;
|
||||
let iconplaypause = Icons.GetIcon('pause'); //pause
|
||||
let shuffle_icon = Icons.GetIcon('shuffle-variant'); //shuffle
|
||||
let onoffbutton = 1374;
|
||||
@@ -5340,9 +5348,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if (shuffle == 'off' || shuffle == false || shuffle == 0 || shuffle == 'false') {
|
||||
shuffle_icon = Icons.GetIcon('shuffle-disabled'); //shuffle
|
||||
}
|
||||
|
||||
// Todo: Refresh automatisieren und dafür wieder Shuffle nutzen
|
||||
//if (v2Adapter == 'volumio') { shuffle_icon = Icons.GetIcon('shuffle-disabled'); } //Volumio: refresh playlist
|
||||
if (v2Adapter == 'volumio') { shuffle_icon = Icons.GetIcon('refresh'); } //Volumio: refresh playlist
|
||||
|
||||
|
||||
//For all players
|
||||
@@ -5373,7 +5379,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
}
|
||||
}
|
||||
|
||||
let currentSpeaker: string = findLocale('media','no_speaker_found');
|
||||
let currentSpeaker = findLocale('media','no_speaker_found');
|
||||
|
||||
if (v2Adapter == 'alexa2') {
|
||||
currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'Echo-Devices.', page.items[0].mediaDevice, '.Info.name'].join(''))).val;
|
||||
@@ -5385,8 +5391,6 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'Players.', page.items[0].mediaDevice, '.Playername'].join(''))).val;
|
||||
} else if (v2Adapter == 'bosesoundtouch') {
|
||||
currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'deviceInfo.name'].join(''))).val;
|
||||
} else if (v2Adapter == 'volumio') {
|
||||
currentSpeaker = getState(([page.items[0].adapterPlayerInstance, 'info.name'].join(''))).val;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------
|
||||
// All Alexa devices (the online / player and commands directory is available) are listed and linked below
|
||||
@@ -5403,11 +5407,6 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
speakerListArray.push(getState(playerId).val);
|
||||
page.items[0].speakerList = speakerListArray;
|
||||
});
|
||||
} else if (v2Adapter == 'spotify-premium') {
|
||||
// All possible Devices if page.items[0].speakerList empty
|
||||
if (Debug) log(getState(page.items[0].adapterPlayerInstance + 'devices.availableDeviceListString').val);
|
||||
speakerListArray = (getState(page.items[0].adapterPlayerInstance + 'devices.availableDeviceListString').val).split(';');
|
||||
page.items[0].speakerList = speakerListArray;
|
||||
} else {
|
||||
let i_list = Array.prototype.slice.apply($('[state.id="' + page.items[0].adapterPlayerInstance + 'Echo-Devices.*.Info.name"]'));
|
||||
for (let i_index in i_list) {
|
||||
@@ -5433,7 +5432,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if (speakerListArray.length > 0) {
|
||||
speakerListIconCol = rgb_dec565(HMIOn);
|
||||
speakerListString = 'input_sel' + '~' +
|
||||
tid + '?speakerlist' + '~' +
|
||||
id + '?speakerlist' + '~' +
|
||||
Icons.GetIcon('speaker') + '~' +
|
||||
speakerListIconCol + '~' +
|
||||
findLocale('media','speaker') + '~' +
|
||||
@@ -5467,13 +5466,10 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
});
|
||||
|
||||
}
|
||||
/* Spotify: get all playlists if empty */
|
||||
} else if (v2Adapter == 'spotify-premium') {
|
||||
page.items[0].playList = (getState(page.items[0].adapterPlayerInstance + 'playlists.playlistListString').val).split(';');
|
||||
}
|
||||
playListIconCol = rgb_dec565(HMIOn);
|
||||
playListString = 'input_sel' + '~' +
|
||||
tid + '?playlist' + '~' +
|
||||
id + '?playlist' + '~' +
|
||||
Icons.GetIcon('playlist-play') + '~' +
|
||||
playListIconCol + '~' +
|
||||
//'PlayL ' + page.heading + '~' +
|
||||
@@ -5483,7 +5479,9 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
|
||||
//InSel Tracklist
|
||||
globalTracklist = ''
|
||||
|
||||
if (v2Adapter == 'spotify-premium') {
|
||||
globalTracklist = ' ' //Todo
|
||||
}
|
||||
let trackListString: string = '~~~~~~'
|
||||
let trackListIconCol = rgb_dec565(HMIOff);
|
||||
if (v2Adapter == 'volumio') { /* Volumio: get queue */
|
||||
@@ -5534,19 +5532,12 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
trackList = trackList + ']';
|
||||
if (Debug) log(trackList, 'info');
|
||||
globalTracklist = trackList;
|
||||
} else if (v2Adapter == 'spotify-premium') {
|
||||
try {
|
||||
let tempTrackList = JSON.parse(getState(page.items[0].adapterPlayerInstance + 'player.playlist.trackListArray').val);
|
||||
globalTracklist = tempTrackList;
|
||||
} catch {
|
||||
log('Hello Mr. Developer something went wrong in tracklist!', 'debug')
|
||||
}
|
||||
}
|
||||
|
||||
if (globalTracklist != null && globalTracklist.length != 0) {
|
||||
trackListIconCol = rgb_dec565(HMIOn);
|
||||
trackListString = 'input_sel' + '~' +
|
||||
tid + '?tracklist' + '~' +
|
||||
id + '?tracklist' + '~' +
|
||||
Icons.GetIcon('animation-play-outline') + '~' +
|
||||
trackListIconCol + '~' +
|
||||
findLocale('media','tracklist') + '~' +
|
||||
@@ -5559,7 +5550,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if (page.items[0].equalizerList != undefined) {
|
||||
equalizerListIconCol = rgb_dec565(HMIOn);
|
||||
equalizerListString = 'input_sel' + '~' +
|
||||
tid + '?equalizer' + '~' +
|
||||
id + '?equalizer' + '~' +
|
||||
Icons.GetIcon('equalizer-outline') + '~' +
|
||||
equalizerListIconCol + '~' +
|
||||
findLocale('media','equalizer') + '~' +
|
||||
@@ -5568,7 +5559,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
let equalizerListIconCol = rgb_dec565(HMIOn);
|
||||
//equalizerListString is used for favariteList
|
||||
equalizerListString = 'input_sel' + '~' +
|
||||
tid + '?favorites' + '~' +
|
||||
id + '?favorites' + '~' +
|
||||
Icons.GetIcon('playlist-star') + '~' +
|
||||
equalizerListIconCol + '~' +
|
||||
findLocale('media','favorites') + '~' +
|
||||
@@ -5617,10 +5608,15 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
repeatIcon = Icons.GetIcon('repeat');
|
||||
repeatIconCol = rgb_dec565(HMIOn);
|
||||
}
|
||||
/*
|
||||
else {
|
||||
repeatIcon = Icons.GetIcon('repeat-off');
|
||||
}
|
||||
*/
|
||||
} else if (v2Adapter == 'volumio') { /* Volumio: only Repeat true/false with API */
|
||||
if (getState(id + '.REPEAT').val == true) {
|
||||
repeatIcon = Icons.GetIcon('repeat-variant');
|
||||
repeatIconCol = rgb_dec565(HMIOn);
|
||||
repeatIconCol = rgb_dec565(colMediaIcon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5631,7 +5627,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
v2Adapter == 'volumio' ||
|
||||
v2Adapter == 'squeezeboxrpc') {
|
||||
repeatButtonString = 'button' + '~' +
|
||||
tid + '?repeat' + '~' +
|
||||
id + '?repeat' + '~' +
|
||||
repeatIcon + '~' +
|
||||
repeatIconCol + '~' +
|
||||
'Repeat' + '~' +
|
||||
@@ -5644,14 +5640,14 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
if (v2Adapter == 'sonos') {
|
||||
if (page.items[0].crossfade == undefined || page.items[0].crossfade == false) {
|
||||
toolsString = 'input_sel' + '~' +
|
||||
tid + '?seek' + '~' +
|
||||
id + '?seek' + '~' +
|
||||
media_icon + '~' +
|
||||
toolsIconCol + '~' +
|
||||
findLocale('media','seek') + '~' +
|
||||
'media5~'
|
||||
} else {
|
||||
toolsString = 'input_sel' + '~' +
|
||||
tid + '?crossfade' + '~' +
|
||||
id + '?crossfade' + '~' +
|
||||
media_icon + '~' +
|
||||
toolsIconCol + '~' +
|
||||
findLocale('media','crossfade') + '~' +
|
||||
@@ -5660,16 +5656,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
} else if (v2Adapter == 'squeezeboxrpc') {
|
||||
if (page.items[0].crossfade == undefined || page.items[0].crossfade == false) {
|
||||
toolsString = 'input_sel' + '~' +
|
||||
tid + '?seek' + '~' +
|
||||
media_icon + '~' +
|
||||
toolsIconCol + '~' +
|
||||
findLocale('media','seek') + '~' +
|
||||
'media5~'
|
||||
}
|
||||
} else if (v2Adapter == 'spotify-premium') {
|
||||
if (page.items[0].crossfade == undefined || page.items[0].crossfade == false) {
|
||||
toolsString = 'input_sel' + '~' +
|
||||
tid + '?seek' + '~' +
|
||||
id + '?seek' + '~' +
|
||||
media_icon + '~' +
|
||||
toolsIconCol + '~' +
|
||||
findLocale('media','seek') + '~' +
|
||||
@@ -5677,7 +5664,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
}
|
||||
} else {
|
||||
toolsString = 'button' + '~' +
|
||||
tid + '' + '~' +
|
||||
id + '' + '~' +
|
||||
media_icon + '~' +
|
||||
toolsIconCol + '~' +
|
||||
findLocale('media','tools') + '~' +
|
||||
@@ -5688,7 +5675,7 @@ function GenerateMediaPage(page: NSPanel.PageMedia): NSPanel.Payload[] {
|
||||
payload: 'entityUpd~' + //entityUpd
|
||||
name + '~' + //heading
|
||||
GetNavigationString(pageId) + '~' + //navigation
|
||||
tid + '~' + //internalNameEntiy
|
||||
id + '~' + //internalNameEntiy
|
||||
title + '~' + //title
|
||||
rgb_dec565(colMediaTitle) + '~' + //titleColor
|
||||
author + '~' + //author
|
||||
@@ -6107,6 +6094,8 @@ function subscribePowerSubscriptions(id: string): void {
|
||||
function GeneratePowerPage(page: NSPanel.PagePower): NSPanel.Payload[] {
|
||||
try {
|
||||
|
||||
if (!page.items[0].id) throw new Error ('Missing pageItem.id for PowerPage!');
|
||||
|
||||
let obj:object = {};
|
||||
let demoMode = false;
|
||||
if (page.items[0].id == undefined){
|
||||
@@ -6633,20 +6622,19 @@ function HandleButtonEvent(words: any): void {
|
||||
|
||||
switch (deviceAdapterRP) {
|
||||
case 'spotify-premium':
|
||||
if (Debug) log(getState(id + '.REPEAT').val);
|
||||
let stateSpotifyRepeat = getState(id + '.REPEAT').val;
|
||||
if (stateSpotifyRepeat == 'off') {
|
||||
setIfExists(id + '.REPEAT', 'context');
|
||||
} else if (stateSpotifyRepeat == 'context') {
|
||||
setIfExists(id + '.REPEAT', 'track');
|
||||
} else if (stateSpotifyRepeat == 'track') {
|
||||
setIfExists(id + '.REPEAT', 'off');
|
||||
let stateSpotifyRepeat = getState(id + '.REPEAT').val
|
||||
if (stateSpotifyRepeat == 'none') {
|
||||
setIfExists(id + '.REPEAT', 'all');
|
||||
} else if (stateSpotifyRepeat == 'all') {
|
||||
setIfExists(id + '.REPEAT', 'one');
|
||||
} else if (stateSpotifyRepeat == 'one') {
|
||||
setIfExists(id + '.REPEAT', 'none');
|
||||
}
|
||||
GeneratePage(activePage!);
|
||||
break;
|
||||
case 'bosesoundtouch':
|
||||
if (Debug) log(adapterInstanceRepeat);
|
||||
let stateBoseRepeat = getState(id + '.REPEAT').val;
|
||||
let stateBoseRepeat = getState(id + '.REPEAT').val
|
||||
if (stateBoseRepeat == 'REPEAT_OFF') {
|
||||
setIfExists(adapterInstanceRepeat + 'key', 'REPEAT_ALL');
|
||||
} else if (stateBoseRepeat == 'REPEAT_ALL') {
|
||||
@@ -6657,7 +6645,7 @@ function HandleButtonEvent(words: any): void {
|
||||
GeneratePage(activePage!);
|
||||
break;
|
||||
case 'sonos':
|
||||
let stateSonosRepeat = getState(id + '.REPEAT').val;
|
||||
let stateSonosRepeat = getState(id + '.REPEAT').val
|
||||
if (stateSonosRepeat == 0) {
|
||||
setIfExists(id + '.REPEAT', 1);
|
||||
} else if (stateSonosRepeat == 1) {
|
||||
@@ -6956,11 +6944,15 @@ function HandleButtonEvent(words: any): void {
|
||||
break;
|
||||
}
|
||||
case 'volumeSlider':
|
||||
subscribeMediaSubscriptions(id);
|
||||
useMediaEvents = true;
|
||||
pageCounter = 1;
|
||||
let vVolume = scale(parseInt(words[4]), 100, 0, activePage!.items[0]!.minValue ?? 0, activePage!.items[0]!.maxValue ?? 100);
|
||||
setIfExists(id + '.VOLUME', Math.floor(vVolume));
|
||||
pageCounter = -1;
|
||||
(function () { if (timeoutSlider) { clearTimeout(timeoutSlider); timeoutSlider = null; } })();
|
||||
timeoutSlider = setTimeout(async function () {
|
||||
setIfExists(id + '.VOLUME', parseInt(words[4]));
|
||||
setTimeout(async function () {
|
||||
pageCounter = 1;
|
||||
GeneratePage(activePage!);
|
||||
}, 3000);
|
||||
}, 20);
|
||||
break;
|
||||
case 'mode-speakerlist':
|
||||
let pageItem = findPageItem(id);
|
||||
@@ -7084,9 +7076,8 @@ function HandleButtonEvent(words: any): void {
|
||||
|
||||
switch (deviceAdapterTL) {
|
||||
case 'spotify-premium':
|
||||
//let trackArray = (function () { try {return JSON.parse(getState(pageItemTL.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})();
|
||||
//setState(adapterInstanceTL + 'player.trackId', getAttr(trackArray, words[4] + '.id'));
|
||||
setState(adapterInstanceTL + 'player.playlist.trackNo', parseInt(words[4]) + 1);
|
||||
let trackArray = (function () { try {return JSON.parse(getState(pageItemTL.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})();
|
||||
setState(adapterInstanceTL + 'player.trackId', getAttr(trackArray, words[4] + '.id'));
|
||||
break;
|
||||
case 'sonos':
|
||||
setState(adapterInstanceTL + 'root.' + pageItemTL.mediaDevice + '.current_track_number', parseInt(words[4]) + 1);
|
||||
@@ -7164,7 +7155,6 @@ function HandleButtonEvent(words: any): void {
|
||||
let deviceAdapterSK: NSPanel.PlayerType = adapterSK[0] as NSPanel.PlayerType;
|
||||
switch (deviceAdapterSK) {
|
||||
case 'spotify-premium':
|
||||
setState(adapterInstanceSK + 'player.progressPercentage', parseInt(words[4]) * 10);
|
||||
break;
|
||||
case 'squeezeboxrpc':
|
||||
const vDuration: number = getState(adapterInstanceSK + 'Players.' + pageItemSeek.mediaDevice + '.Duration').val;
|
||||
@@ -8262,11 +8252,6 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti
|
||||
actualState = Math.round(actualStateTemp / 10) * 10 + '%';
|
||||
optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%';
|
||||
}
|
||||
if (vAdapter == 'spotify-premium') {
|
||||
const actualStateTemp: number = getState(pageItem.adapterPlayerInstance + 'player.progressPercentage').val;
|
||||
actualState = Math.round(actualStateTemp / 10) * 10 + '%';
|
||||
optionalString = '0%?10%?20%?30%?40%?50%?60%?70%?80%?90%?100%';
|
||||
}
|
||||
if (vAdapter == 'squeezeboxrpc') {
|
||||
const actualStateTime: number = parseInt(getState(pageItem.adapterPlayerInstance + 'Players.' + pageItem.mediaDevice + '.Time').val);
|
||||
const actualStateDuration: number = parseInt(getState(pageItem.adapterPlayerInstance + 'Players.' + pageItem.mediaDevice + '.Duration').val);
|
||||
@@ -8409,7 +8394,7 @@ function GenerateDetailPage(type: NSPanel.PopupType, optional: NSPanel.mediaOpti
|
||||
//Limit 900 characters, then memory overflow --> Shorten as much as possible
|
||||
let temp_array: any[] = [];
|
||||
//let trackArray = (function () { try {return JSON.parse(getState(pageItem.adapterPlayerInstance + 'player.playlist.trackListArray').val);} catch(e) {return {};}})();
|
||||
for (let track_index = 0; track_index < 48; track_index++) {
|
||||
for (let track_index = 0; track_index < 45; track_index++) {
|
||||
let temp_cut_array = getAttr(globalTracklist, track_index + '.title');
|
||||
/* Volumio: @local/NAS no title -> name */
|
||||
if (temp_cut_array == undefined) {
|
||||
@@ -8854,10 +8839,9 @@ function HandleScreensaverUpdate(): void {
|
||||
iconColor + '~' +
|
||||
config.bottomScreensaverEntity[4].ScreensaverEntityText + '~' +
|
||||
val
|
||||
} // Ende zusätzlichen Status Alternativ Layout
|
||||
}
|
||||
|
||||
} else {
|
||||
// USER definierte Bottom Entities
|
||||
let checkpoint = true;
|
||||
let i = 0;
|
||||
for (i = 0; i < maxEntities - 1 && i < config.bottomScreensaverEntity.length; i++) {
|
||||
@@ -8911,7 +8895,7 @@ function HandleScreensaverUpdate(): void {
|
||||
}
|
||||
}
|
||||
|
||||
const temp = config.bottomScreensaverEntity[i].ScreensaverEntityIconColor
|
||||
const temp = config.bottomScreensaverEntity[4].ScreensaverEntityIconColor
|
||||
if (temp && typeof temp == 'string' && existsObject(temp)) {
|
||||
iconColor = getState(temp).val;
|
||||
}
|
||||
@@ -8982,8 +8966,6 @@ function HandleScreensaverUpdate(): void {
|
||||
SendToPanel({ payload: 'weatherUpdate~' + payloadString });
|
||||
|
||||
HandleScreensaverStatusIcons();
|
||||
|
||||
HandleScreensaverColors();
|
||||
}
|
||||
|
||||
} catch (err: any) {
|
||||
@@ -9978,7 +9960,7 @@ namespace NSPanel {
|
||||
export type SerialType = 'button' | 'light' | 'shutter' | 'text' | 'input_sel' | 'timer' | 'number' | 'fan'
|
||||
|
||||
export type roles = 'light' |'socket'|'dimmer'| 'hue' | 'rgb' | 'rgbSingle' | 'ct' | 'blind' | 'door' | 'window' | 'volumeGroup' | 'volume'
|
||||
| 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning'
|
||||
| 'info' | 'humidity' | 'temperature' | 'value.temperature' | 'value.humidity' | 'sensor.door' | 'sensor.window' | 'thermostat' | 'warning' | 'ct'
|
||||
| 'cie' | 'gate' | 'motion' | 'buttonSensor' | 'button' | 'value.time' | 'level.timer' | 'value.alarmtime' | 'level.mode.fan' | 'lock' | 'slider'
|
||||
| 'switch.mode.wlan' | 'media' | 'timeTable' | 'airCondition'
|
||||
|
||||
@@ -10038,7 +10020,7 @@ namespace NSPanel {
|
||||
|
||||
export type PageGrid2 = {
|
||||
type: 'cardGrid2',
|
||||
items: [PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?],
|
||||
items: [PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?, PageItem?],
|
||||
} & PageBaseType
|
||||
|
||||
export type PageThermo = {
|
||||
@@ -10142,6 +10124,7 @@ namespace NSPanel {
|
||||
navigate?: boolean,
|
||||
colormode?: string,
|
||||
colorScale?: IconScaleElement,
|
||||
//adapterPlayerInstance?: adapterPlayerInstanceType,
|
||||
targetPage?: string,
|
||||
modeList?: string[],
|
||||
hidePassword?: boolean,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-config
|
||||
name: NSPanel Lovelace UI Addon
|
||||
version: "4.7.80"
|
||||
version: "4.7.78"
|
||||
slug: nspanel-lovelace-ui
|
||||
description: NSPanel Lovelace UI Addon
|
||||
services:
|
||||
|
||||
@@ -209,11 +209,11 @@ class HAEntity(panel_cards.Entity):
|
||||
forecast = libs.home_assistant.execute_script(
|
||||
entity_name=self.entity_id,
|
||||
domain='weather',
|
||||
service="get_forecasts",
|
||||
service="get_forecast",
|
||||
service_data={
|
||||
'type': forecast_type
|
||||
}
|
||||
).get(self.entity_id,{}).get("forecast", [])
|
||||
).get("forecast", [])
|
||||
if len(forecast) > pos:
|
||||
forcast_pos = forecast[pos]
|
||||
forcast_condition = forcast_pos.get("condition", "")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
paho-mqtt==1.6.1
|
||||
paho-mqtt
|
||||
pyyaml
|
||||
websockets
|
||||
websocket-client
|
||||
@@ -7,4 +7,4 @@ python-dateutil
|
||||
scheduler
|
||||
babel
|
||||
watchdog
|
||||
jinja2
|
||||
jinja2
|
||||
Reference in New Issue
Block a user