NxPanel - Replacement Firmware for Sonoff NSPanel

Edit: I solved it the topic was wrong in my case it needs to be cmnd/tasmota_32AC64/nspanel/nxpanel

I cant get any mqtt cmnd updates to work.

I tried to send:
Topic:cmnd/nspanel/nxpanel

message: {"refresh":{"pid":10,"name":"Lounge","format":6,buttons:[{"bid":1,"label":"Movie","type":1,"state":1,"icon":1},{"bid":2,"label":"Lounge","type":1,"state":0,"icon":1},{"bid":3,"label":"Hall","type":2,"icon":6},{"bid":4,"label":"Bedroom","type":10,"next":11,"state":5,"icon":5},{"bid":5,"label":"Temp","type":10,"next":15,"state":9,"icon":9},{"bid":6,"label":"Light","type":3,"next":18,"state":1,"icon":2},{"bid":7,"label":"Dimmer","type":4,"next":16,"state":0,"icon":3},{"bid":8,"label":"Status","type":10,"next":19,"state":15,"icon":16}]}}

But in the tasmota console the cmd is not even recognized.

What does work when I type onto the tasmota console:
nxpanel {"refresh":{"pid":10,"name":"Lounge","format":6,buttons:[{"bid":1,"label":"Movie","type":1,"state":1,"icon":1},{"bid":2,"label":"Lounge","type":1,"state":0,"icon":1},{"bid":3,"label":"Hall","type":2,"icon":6},{"bid":4,"label":"Bedroom","type":10,"next":11,"state":5,"icon":5},{"bid":5,"label":"Temp","type":10,"next":15,"state":9,"icon":9},{"bid":6,"label":"Light","type":3,"next":18,"state":1,"icon":2},{"bid":7,"label":"Dimmer","type":4,"next":16,"state":0,"icon":3},{"bid":8,"label":"Status","type":10,"next":19,"state":15,"icon":16}]}}

Console log:

13:14:01.493 MQT: tele/tasmota_32AC64/RESULT = {"page": {"format": 6, "pid": 10, "type": "sync"}}
13:14:03.491 MQT: tele/tasmota_32AC64/RESULT = {"page": {"format": 6, "pid": 10, "type": "sync"}}
13:14:05.493 MQT: tele/tasmota_32AC64/RESULT = {"page": {"format": 6, "pid": 10, "type": "sync"}}
13:14:07.515 MQT: tele/tasmota_32AC64/RESULT = {"page": {"format": 6, "pid": 10, "type": "sync"}}
13:14:09.492 MQT: tele/tasmota_32AC64/RESULT = {"page": {"format": 6, "pid": 10, "type": "sync"}}
13:14:11.496 MQT: tele/tasmota_32AC64/RESULT = {"page": {"format": 6, "pid": 10, "type": "sync"}}
13:14:13.491 MQT: tele/tasmota_32AC64/RESULT = {"page": {"format": 6, "pid": 10, "type": "sync"}}
13:14:14.666 CMD: nxpanel {"refresh":{"pid":10,"name":"Lounge","format":6,buttons:[{"bid":1,"label":"Movie","type":1,"state":1,"icon":1},{"bid":2,"label":"Lounge","type":1,"state":0,"icon":1},{"bid":3,"label":"Hall","type":2,"icon":6},{"bid":4,"label":"Bedroom","type":10,"next":11,"state":5,"icon":5},{"bid":5,"label":"Temp","type":10,"next":15,"state":9,"icon":9},{"bid":6,"label":"Light","type":3,"next":18,"state":1,"icon":2},{"bid":7,"label":"Dimmer","type":4,"next":16,"state":0,"icon":3},{"bid":8,"label":"Status","type":10,"next":19,"state":15,"icon":16}]}}
13:14:15.230 MQT: stat/tasmota_32AC64/RESULT = {"NxPanel":"Done"}
13:14:17.870 MQT: tele/tasmota_32AC64/RESULT = {"button": {"pid": 10, "bid": 2, "state": 1, "next": 0}} 
13:14:18.668 MQT: tele/tasmota_32AC64/RESULT = {"button": {"pid": 10, "bid": 2, "state": 0, "next": 0}}

Any ideas?

I am stuck with the next issue, the trigger does not work in the rule.

This is my rule:

configuration: {}
triggers:
  - id: "1"
    configuration:
      channelUID: mqtt:broker:0d7e24f360:nxpanel_page_trigger
    type: core.ChannelEventTrigger
conditions: []
actions:
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript;version=ECMAScript-2021
      script: console.log('rule triggered update from nspannel');
    type: script.ScriptAction
  - inputs: {}
    id: "2"
    configuration:
      considerConditions: true
      ruleUIDs:
        - d189a8c221
    type: core.RunRuleAction

the message does never show in the log. So this rule is not triggered.
How are the Items and channels are configured that they trigger?
I am able to set the cmd text on the item but the linked mqtt channel does not send it to the broker.

Hi Mike,

Good to hear you are picking up development again.
I have used NxPanel for approx 1.5 month and it worked quite well, and had to take it down 3 weeks ago :slightly_frowning_face:, until my house is remodelled… But once my house is finished I am planning to put 4 Nxpanels into it.

During my usage I ran into the following issues:

  1. Documentation is scarce, difficult to find and not complete.
    Could you provide some examples on how to use each command and place it on your git hub together with the code?
    I think that this really would help alot of users,
  2. I am also missing the auto home feature.
  3. I would also like to be able to control the active screen remotely, now it can only be changed upon request from the NxPanel.
  4. Could you add your Nextion design files to your Git hub as welll ?
    This would allow user to fi. add their own icons.
    Although I like the GUI of NxPanel, and its flexibility, I am missing some icons that I need for my home-automation, which would be a reason to switch firmware in the future.
    I know that you can not put every icon in, but sharing the Nextion files, at least allows more advanced users to add their own.
    I do know that the Nextion editor is not nice to work with, but its doable.

These are my missing things that I ran into during my use.

Keep up the good work :+1:
Best Regards,

Robin

Hi,

I’m thinking of buying a NSPanel and I would like to know if it is working good as a thermostat with the Tasmota firmware?
Are you using it with a PID Controller or how does it work?

Best regards
Andy

where is the “make sure you tick auto update and also test updates in the config panel” ?
you mean in tasmota web interface or somewhere else?

The whole project is awesome so far. But is there any chance that the hmi file get’s published to change the UI design?

Edit: I now wrote a script for the Lovelace UI project and changed the graphics of the screensaver page and added a swipe function (left,right,up,down). Works better for me.


where is that setting???
can someone explain.
thank you in advance

Swipe down from the home screen and you should see these settings.

thank you, didnt notice it. its there

You should look at the NSPanel Lovelace UI. There is no OpenHab integration right now and my script is not ready to publish. I also didn’t make it configurable but hard-coded the pages in a rule script due to lack of time. But the syntax is very easy to integrate once one has the list of the commands.

They have a very extensive icon list integrated as a font:
https://docs.nspanel.pky.eu/icon-cheatsheet.html

@InTim Could you please share your rule script?

Is there a way to disable the screensaver or to modify to show a configured page, like lights or barcode thermostat etc? Thank you!

Interested in playing with this. (Sorry Mike, I’m only looking!)
How is the backend done for this one in openHAB? Is that what you mean by the script?
Did you take the backend for AppDaemon? I’ve never used HA, am trying to find the code to convert it

I’ll share it for whoever wants to work on it. It a bit messy and unfinished, but shows the way how I did it. I also add the hmi file. The original Lovelace NSPanel screen will send ‘bExit’ on touch at the screensaver page. Whis one will use ‘swipeLeft’/‘swipeRight’/… Just change it to whatever you need.

We start with a rule definition. I use a trigger channel on NSPanel_xxxx/tele/RESULT
I also use a cron for periodic updates and the changing weather screen (current weather and forecast)
And then there are trigger channels for the relais and by choice other events that would need to trigger a screen update.

The script is written in groovy.

import org.slf4j.LoggerFactory
import org.openhab.core.transform.actions.Transformation
import org.openhab.core.items.events.ItemCommandEvent

// Setting
mqtt              = actions.get("mqtt","mqtt:broker:e362dd1c39")
TOPIC             = "NSPanel_3A78/cmnd/CustomSend"
loc               = Locale.GERMAN;  
brightness_dimm   = 50  
brightness_normal = 100
timeout           = 5      // in seconds
textcolor         = [230,230,230]  // default text color
backgroundcolor   = 0      // default background Color

// Definitions
Calendar currentDate  = new GregorianCalendar(loc)
logger                = LoggerFactory.getLogger("org.openhab.core.automation.nspanel")
colors                = ["color"]           // Define colors array [0]
colors[1]             = backgroundcolor     // Define background color

// Avoid errors for missing property
def propertyMissing( propertyname ) {
    if (propertyname == "updateCount") { def value = 0 }       // Initial value for update counter if not defined
    if (propertyname == "event")       { def value = "cron" }  // Check if channel trigger event() exists. If not the script was started by a cron!
}

if (this.prevScreen === null) { this.prevScreen = this.screen }

logger.info("CURRENT SCREEN "+this.prevScreen+" - PREV. SCREEN "+this.screen) 

////////////// Script was triggered by a cron - periodic update //////////////

if (event == "cron") {

  if (this.updateCount == null)                             { this.updateCount = 0 }          // Initialize update count for periodically changing screens
  if (this.screen === "undefined" || this.screen === null)  { this.screen = "screensaver" ; mqtt.publishMQTT(TOPIC, "pageType~screensaver~~~")}   // In case no page defined - open screensaver page
  this.updateCount++

  ScreenSaver(currentDate)                                  
  logger.info("NSPanel Script(38) Trigger Event: Cron")

////////////// Script was triggered by the channel - execute action //////////////

} else {

  str = event.getEvent();                                 logger.info("NSPanel Script(44) Trigger Event: "+str)


///////////////////////////////////
/////       Navigation       //////
///////////////////////////////////

  // Parse events
  if (str.contains("event"))              // MQTT message with 'event' received
    {
      // Message contains 'startup' - go to screensaver page - standard: "event,startup,42,eu"
      if (str.contains("startup"))
      {
          this.screen = "screensaver"
          mqtt.publishMQTT(TOPIC, "pageType~screensaver~~~")
          ScreenSaver(currentDate)

      }

      // TOUCHSCREEN EVENT - example: "event,screensaver,swipeRight"
      else if (str.contains("screensaver")) 
      {
          this.screen = "screensaver"
          if (str.contains("swipeRight")) { GridPage()    }        // EXIT SCREENSAVER - go to grid page
          if (str.contains("swipeLeft"))  { ThermoPage()  }      // EXIT SCREENSAVER - go to thermostat page
      }
      // TOUCHSCREEN EVENT - example: "event,cardGrid,bPrev"
      else if (str.contains("cardGrid"))
      {
          this.screen = "gridscreen1"
          if  (str.contains("bPrev"))  { ScreenSaver(currentDate) }   // EXIT GRID SCREEN - go to screensaver  
      }
      else if (str.contains("sleepReached"))                                        // SLEEP MODE
      {
          logger.info("NSPanel Script(57) Sleep Reached") 
      }
  
  // RELAIS triggered
  } else if ( str == 'ON' || str == 'OFF' ) {
    
    mqtt.publishMQTT(TOPIC, WeatherUpdate(Calendar))
    logger.info("NSPanel Script(62) Relais status changed")
    
  }
}

////////////////////////////////////
///           METHODS             //
////////////////////////////////////
def TimeoutUpdate(timeout) {
  mqtt.publishMQTT(TOPIC, 'timeout~'+timeout)
}

def DimmodeUpdate(brightness_dimm,brightness_normal,backgroundcolor=[0,0,0],fontcolor=[255,255,255]) {
    def cmnd_list = ["dimmode"]
    cmnd_list[1]  = brightness_dimm
    cmnd_list[2]  = brightness_normal
    cmnd_list[3]  = RGB888ToRGB565(*backgroundcolor)
    cmnd_list[4]  = RGB888ToRGB565(*fontcolor)
    return cmnd_list.join("~")
}

def TimeUpdate(Calendar) {  // TIME COMMAND: time ~ xx:xx?AM/PM ~ (tTimeAdd - text below time)
    var Hour         = Calendar.get(Calendar.HOUR_OF_DAY)
    var Minute       = Calendar.get(Calendar.MINUTE)
    var Second       = Calendar.get(Calendar.SECOND)
  
    def cmnd_list = ["time"]
    cmnd_list[1]  = Hour+':'+(Minute<10?("0"+Minute):(Minute))+'?'+(Second<10?("0"+Second):(Second)) // make it two-digit
    cmnd_list[2]  = "" // Additional text
    return cmnd_list.join("~")
}

def DateUpdate(Calendar, loc) {    // DATE COMMAND: date ~ date string
    var dayOfWeek    = Calendar.getDisplayName(Calendar.DAY_OF_WEEK ,Calendar.LONG, loc)
    var monthOfYear  = Calendar.getDisplayName(Calendar.MONTH ,Calendar.LONG, loc)
    var Year         = Calendar.get(Calendar.YEAR)
    var Month        = Calendar.get(Calendar.MONTH)
    var Day          = Calendar.get(Calendar.DAY_OF_MONTH)
    return 'date~'+dayOfWeek+', '+Day+'. '+monthOfYear
}

////////////////////////////////////
///            PAGES              //
////////////////////////////////////

/*------------------------ SCREENSAVER ----------------------- */
// TimeUpdate + DateUpdate + WeatherUpdate + Colors
def ScreenSaver(Calendar) {
  
    if (this.prevScreen === null || this.prevScreen != "screensaver") {
      mqtt.publishMQTT(TOPIC, "pageType~screensaver~~~")
      logger.info("CHANGED PAGE FROM: "+this.prevScreen+" TO: "+this.screen) 
      this.screen = "screensaver"
    }
                         
    // Call TimeUpdate
    cmnd = TimeUpdate(Calendar)
    mqtt.publishMQTT(TOPIC, cmnd);                    //logger.info("NSPanel Script(83) Send command: "+TOPIC+"/"+cmnd)

    // Call DateUpdate
    cmnd = DateUpdate(Calendar, loc)
    mqtt.publishMQTT(TOPIC, cmnd);                    //logger.info("NSPanel Script(87) Send command: "+TOPIC+"/"+cmnd)

    // Call WeatherUpdate - switch between current & forecast
    if (this.updateCount % 2 == 0) 
         { cmnd = WeatherUpdate(Calendar,"forecast") } 
    else { cmnd = WeatherUpdate(Calendar,"current") }
    mqtt.publishMQTT(TOPIC, cmnd);                    //logger.info("NSPanel Script(93) Send command: "+TOPIC+"/"+cmnd)
    mqtt.publishMQTT(TOPIC, Colors());                //logger.info("NSPanel Script(94) Send command: "+TOPIC+"/"+cmnd)
                                                                                 
}


def WeatherUpdate(Calendar,format="forecast") {

  /* weatherUpdate (only if notify not active) ~ MainIcon(1) ~ MainText(2) ~ Forecast1(3) ~ Forecast1Icon(4) ~ Forecast1Value(5)
                                                                            ~ Forecast2(6) ~ Forecast2Icon(7) ~ Forecast2Value(8)
                                                                             ~ Forecast3(9) ~ Forecast3Icon(10) ~ Forecast3Value(11)
                                                                              ~ Forecast4(12) ~ Forecast4Icon(13) ~ Forecast4Value(14)
                                                                               ~ tMRIcon(15) ~ tMR(16) ~ StatusIcon1(17) ~ Icon1Color(18) ~ StatusIcon2(19) ~ Icon2Color(20)
  */
  

  // Available Icons:
  // https://docs.nspanel.pky.eu/icon-cheatsheet.html
  // https://github.com/joBr99/nspanel-lovelace-ui/blob/main/ioBroker/icon_mapping.js#L6741
  
  // FORMAT WEATHER FORECAST 24h
  if (format == "forecast"){
    def Calendar adjustedTime = new GregorianCalendar(loc)
    
    weatherText = []
        weatherText[0] = ""
          adjustedTime.add(Calendar.HOUR_OF_DAY, 6);
        weatherText[1] = adjustedTime.get(Calendar.HOUR_OF_DAY)+" Uhr"
          adjustedTime.add(Calendar.HOUR_OF_DAY, 6);
        weatherText[2] = adjustedTime.get(Calendar.HOUR_OF_DAY)+" Uhr"
          adjustedTime.add(Calendar.HOUR_OF_DAY, 6);
        weatherText[3] = adjustedTime.get(Calendar.HOUR_OF_DAY)+" Uhr"
          adjustedTime.add(Calendar.HOUR_OF_DAY, 6);
        weatherText[4] = adjustedTime.get(Calendar.HOUR_OF_DAY)+" Uhr"
    
    weatherIcon = []
        weatherIcon[0] = Transformation.transform("MAP", "OpenWeatherIcons.map", items.get('Wettervorhersage_IconID').toString())
        colors[5] = RGB888ToRGB565(255,200,100)
        weatherIcon[1] = Transformation.transform("MAP", "OpenWeatherIcons.map", items.get('Wettervorhersage_6Hour_IconID').toString())
        weatherIcon[2] = Transformation.transform("MAP", "OpenWeatherIcons.map", items.get('Wettervorhersage_12Hour_IconID').toString())
        weatherIcon[3] = Transformation.transform("MAP", "OpenWeatherIcons.map", items.get('Wettervorhersage_18Hour_IconID').toString())
        weatherIcon[4] = Transformation.transform("MAP", "OpenWeatherIcons.map", items.get('Wettervorhersage_24Hour_IconID').toString())
  
    weatherValue = []
        weatherValue[0] = (items.get('Wettervorhersage_Aussentemperatur') as int)+"°C"
        weatherValue[1] = (items.get('Wettervorhersage_6Hour_Temp') as int)+"°C"
        weatherValue[2] = (items.get('Wettervorhersage_12Hour_Temp') as int)+"°C"
        weatherValue[3] = (items.get('Wettervorhersage_18Hour_Temp') as int)+"°C"
        weatherValue[4] = (items.get('Wettervorhersage_24Hour_Temp') as int)+"°C"

  // FORMAT CURRENT CONDITIONS
  } else if (format == "current") {
    weatherText = []
        weatherText[0] = items.get('WeatherandForecast_WeatherCondition').toString()
        weatherText[1] = "Chill"
        weatherText[2] = "Regen"
        weatherText[3] = "Wind"
        weatherText[4] = "Wolken"
   
    weatherIcon = []
        weatherIcon[0] = Transformation.transform("MAP", "OpenWeatherIcons.map", items.get('Wettervorhersage_IconID').toString())
        colors[5] = RGB888ToRGB565(255,200,100)
        weatherIcon[1] = Transformation.transform("MAP", "OpenWeatherIcons.map", "thermometer")
        weatherIcon[2] = Transformation.transform("MAP", "OpenWeatherIcons.map", "weather-pouring")
        weatherIcon[3] = Transformation.transform("MAP", "OpenWeatherIcons.map", "weather-windy")
        weatherIcon[4] = Transformation.transform("MAP", "OpenWeatherIcons.map", "weather-cloudy")
    
    // default txt color = 57084
    // 38027 = moon
    // 54749 = sun
    // 13052 = rain
    // 50712 = neutral grey
    //colors[5] = "38027"
    //colors[11] = "50712"
    //colors[12] = "13052"
    //colors[13] = "50712"
    //colors[14] = "50712"

    
  
    weatherValue = []
        weatherValue[0] = (items.get('Wettervorhersage_Aussentemperatur') as int)+"°C"
        weatherValue[1] = (items.get('Wetter_Windchill') as int)+"°C"
        weatherValue[2] = new Float(items.get('Wetter_Regen').toString().replaceAll(" mm", ""))+"mm"
        weatherValue[3] = (items.get('Wetter_Windgeschwindigkeit') as int)+"km/h"
        weatherValue[4] = (items.get('Wetter_Bewolkung') as int)+"%"
  }

    def cmnd_list     = ["weatherUpdate"]
        cmnd_list[1]  = Transformation.transform("MAP", "LovelaceIcons.map", weatherIcon[0])       // Main Icon
        cmnd_list[2]  = weatherValue[0]                                                           // Main Text
        cmnd_list[3]  = weatherText[1]                                                            // Forecast 1 Text
        cmnd_list[4]  = Transformation.transform("MAP", "LovelaceIcons.map", weatherIcon[1])      // Forecast 1 Icon
        cmnd_list[5]  = weatherValue[1]                                                           // Forecast 1 Value
        cmnd_list[6]  = weatherText[2]                                                            // Forecast 2 Text
        cmnd_list[7]  = Transformation.transform("MAP", "LovelaceIcons.map", weatherIcon[2])       // Forecast 2 Icon
        cmnd_list[8]  = weatherValue[2]                                                           // Forecast 2 Value
        cmnd_list[9]  = weatherText[3]                                                            // Forecast 3 Text
        cmnd_list[10] = Transformation.transform("MAP", "LovelaceIcons.map", weatherIcon[3])      // Forecast 3 Icon
        cmnd_list[11] = weatherValue[3]                                                           // Forecast 3 Value
        cmnd_list[12] = weatherText[4]                                                            // Forecast 4 Text
        cmnd_list[13] = Transformation.transform("MAP", "LovelaceIcons.map", weatherIcon[4])      // Forecast 4 Icon
        cmnd_list[14] = weatherValue[4]                                                           // Forecast 4 Value
        cmnd_list[15] = ""                                                                        // TMRIcon
        cmnd_list[16] = ""                                                                        // TMR
        cmnd_list[17] = Transformation.transform("MAP", "LovelaceIcons.map", "lightbulb-on")         // Status 1 Icon
        cmnd_list[18] = (items.get('NSPanel3A78_Relais1') == ON) ? RGB888ToRGB565(255,165,90) : RGB888ToRGB565(35,116,156)             // Status 1 Color
        logger.info("Switch 1: "+items.get('NSPanel3A78_Relais1')+" Color: "+cmnd_list[18])
        cmnd_list[19] = Transformation.transform("MAP", "LovelaceIcons.map", "lightbulb-on")         // Status 2 Icon
        cmnd_list[20] = (items.get('NSPanel3A78_Relais2') == ON) ? RGB888ToRGB565(255,165,90) : RGB888ToRGB565(35,116,156)         // Status 2 Color
        logger.info("Switch 2: "+items.get('NSPanel3A78_Relais2')+" Color: "+cmnd_list[20])

    return cmnd_list.join("~")
}

def Colors() {
  /* color (0) ~ background (1) ~ tTime (2) ~ tAMPM (3) ~ tDate (4) ~ tMainIcon (5) ~ tMainText (6) ~ tForecast1 (7) ~ tForecast2 (8) ~ tForecast3 (9) ~ tForecast4 (10)
                                                                                     ~ tF1Icon (11) ~ tF2Icon (12) ~ tF3Icon (13) ~ tF4Icon (14)
                                                                                      ~ tForecast1Val (15) ~ tForecast2Val (16) ~ tForecast3Val (17) ~ tForecast4Val (18)
                                                                                       ~ t10 (Line) (19) ~ tMRIcon (20) ~ tMRtxt (21) ~ tTimeAdditional (22)
     color~0~46518~46518~46518~38027~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518 -- OK                                                                    
     color~0~46518~46518~46518~38027~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518~46518  -- NOK 
  */
  
  
  // Main Icon
  if      (weatherIcon[0] == 'weather-sunny' || weatherIcon[0] == 'weather-partly-cloudy')        { colors[5] = RGB888ToRGB565(255,165,90) }  // Sun
  else if (weatherIcon[0] == 'weather-night' || weatherIcon[0] == 'weather-night-partly-cloudy')  { colors[5] = RGB888ToRGB565(144,144,88) }  // Moon
  else if (weatherIcon[0] == 'weather-rainy' || weatherIcon[0] == 'weather-partly-rainy' 
                                             || weatherIcon[0] == 'weather-lightning-rainy' 
                                             || weatherIcon[0] == 'weather-pouring')              { colors[5] = RGB888ToRGB565(48,92,224) }   // Rain
  else                                                                                            { colors[5] = RGB888ToRGB565(*textcolor) }  // Default text color
  
  for(int i = 0;i<22;i++) {
    if (colors[i] == null) {
      colors[i] = RGB888ToRGB565(*textcolor)    // anything undefined is default text color
    }
  }
  return colors.join("~")
}

/*------------------------ GRID PAGE ----------------------- */     // entityUpd,heading,navigation, [,type,internalName,iconId,iconColor,displayName,optionalValue]*6

def GridPage() {

    if (this.prevScreen === null || this.prevScreen != "gridscreen1") {
      mqtt.publishMQTT(TOPIC, 'pageType~cardGrid~~~')
      this.screen = "gridscreen1"
      logger.info("CHANGED PAGE FROM: "+this.prevScreen+" TO: "+this.screen) 
    }
  
    def cmnd_list = ["entityUpd"]
    cmnd_list[1]  = "Funktionen"// Heading text
    cmnd_list[2]  = "1|1"       // Navigation
                                // 0= no Prev    |  0= no Next
                                // 1= Prev left  |  1= Next
                                // 2= Prev up    | 
  
    cmnd_list[3]  = "on"        // Entity1 - Type "delete" or "" = invisible
    cmnd_list[4]  = "Btn1"      // Entity1 - Internal name - Touch-Fdbk ="event,buttonPress2,"+entn1.txt+",button"
    cmnd_list[5]  = Transformation.transform("MAP", "LovelaceIcons.map", "light-recessed")  // Entity1 - Icon
    cmnd_list[6]  = "17299"     // Entity1 - IconColor
    cmnd_list[7]  = "Decke"     // Entity1 - DisplayText
    cmnd_list[8]  = ""          // Optional
  
    cmnd_list[9]   = "on"       // Entity2 - Type "delete" or "" = invisible
    cmnd_list[10]  = "Btn2"     // Entity2 - Internal name - Touch-Fdbk ="event,buttonPress2,"+entn1.txt+",button"
    cmnd_list[11]  = Transformation.transform("MAP", "LovelaceIcons.map", "lightbulb-on")           // Entity2 - Icon
    cmnd_list[12]  = "64811"    // Entity2 - IconColor
    cmnd_list[13]  = "Bett links" // Entity2 - DisplayText
    cmnd_list[14]  = ""         // Optional
  
    cmnd_list[15]  = "on"       // Entity3 - Type "delete" or "" = invisible
    cmnd_list[16]  = "Btn3"     // Entity3 - Internal name - Touch-Fdbk ="event,buttonPress2,"+entn1.txt+",button"
    cmnd_list[17]  = Transformation.transform("MAP", "LovelaceIcons.map", "lightbulb")           // Entity3 - Icon
    cmnd_list[18]  = "17299"    // Entity3 - IconColor
    cmnd_list[19]  = "Bett rechts" // Entity3 - DisplayText
    cmnd_list[20]  = ""         // Optional
  
    cmnd_list[21]  = "on"       // Entity4 - Type "delete" or "" = invisible
    cmnd_list[22]  = "Btn4"     // Entity4 - Internal name - Touch-Fdbk ="event,buttonPress2,"+entn1.txt+",button"
    cmnd_list[23]  = Transformation.transform("MAP", "LovelaceIcons.map", "lightbulb-on-outline")           // Entity4 - Icon
    cmnd_list[24]  = "64811"    // Entity4 - IconColor
    cmnd_list[25]  = "Akzent"   // Entity4 - DisplayText
    cmnd_list[26]  = ""         // Optional
 
    cmnd_list[27]  = "on"       // Entity5 - Type "delete" or "" = invisible
    cmnd_list[28]  = "Btn5"     // Entity5 - Internal name - Touch-Fdbk ="event,buttonPress2,"+entn1.txt+",button"
    cmnd_list[29]  = Transformation.transform("MAP", "LovelaceIcons.map", "track-light")           // Entity5 - Icon
    cmnd_list[30]  = "17299"    // Entity5 - IconColor
    cmnd_list[31]  = "Schrank"  // Entity5 - DisplayText
    cmnd_list[32]  = ""         // Optional
  
    cmnd_list[33]  = "delete"   // Entity6 - Type "delete" or "" = invisible
    cmnd_list[34]  = ""         // Entity6 - Internal name - Touch-Fdbk ="event,buttonPress2,"+entn1.txt+",button"
    cmnd_list[35]  = ""         // Entity6 - Icon
    cmnd_list[36]  = ""         // Entity6 - IconColor
    cmnd_list[37]  = ""         // Entity6 - DisplayText
    cmnd_list[38]  = ""         // Optional
    
    cmnd = cmnd_list.join("~") 

    mqtt.publishMQTT(TOPIC, cmnd.toString());     logger.info("NSPanel Script(312) Build page cardGrid - Command: "+TOPIC+"/"+cmnd)
}
////////////////////////////////////
///////      HELPERS          //////
////////////////////////////////////

//logger.info("Color RGB888: "+textcolor+" - Color RGB565: "+RGB888ToRGB565(*textcolor))

int RGB888ToRGB565(red,green,blue) {
    int B = (blue >>> 3) & 0x001F
    int G = ((green >>> 2) << 5) & 0x07E0
    int R = ((red >>> 3) << 11) & 0xF800
    return (R | G | B);
}


if (items.get('nspanel_3a78_screen') != this.screen) {
  events.sendCommand(itemRegistry.get('nspanel_3a78_screen'), this.screen)
}

this.prevScreen = this.screen
logger.info("rule done")

Then for the weather and icon transformations there are .map files

LovelaceIcons.map
OpenWeatherIcons.map

HMI file (for Nextion editor) with background image and swipe.
TFT file for direct upload to panel (you will likely need to modify the .hmi to your needs or use the original Lovelace NSPanel files from github)

background_blank

4 Likes

I’m almost there with this. Got all new items linked, mqtt settings, etc.
The LovelaceIcons.map file link isn’t working. Please could you update?

The map files go into the transform folder, right?
I think my OpenWeather came up with a condition not in the map file, ‘clear sky’.

Here is a new link to the Icons map:https://filebin.net/5hh3lt5f7cmgcqog/LovelaceIcons.map

Yes, map files in the transformation folder.

@InTim

I’m unable to get the HMI file - don’t know if there is any issue at file.io.
Tried to create an account, but can’t login

How do you update the HMI file?

@InTim
What is missing if the RESULT always contains bExit?

{“CustomRecv”:“event,buttonPress2,screensaver,bExit,1”}

We should really seperate these topics from this thread. Any admin here who can do this?
I updated the links and used permanent webspace. Sorry for the unreliability of the free providers.

To my knowledge bExit will only be triggerend when the screen is touched anywhere on the screensaver page. That’s the object TouchCap tc0 in the Nextion editor.

1 Like

Great, thank you!
I get bExit when swiping, too.
Maybe it’s related to the HMI file?
How can it be uploaded?

When trying to flash using openhab/static/… i get this:

get: /static/nspanel_ampm_backgroundimg.tft
09:09:28.912 FLH: Send (High Speed) flash start
09:09:29.318 BRY: Exception> ‘divzero_error’ - division by zero

The same error appears when exporting the TFT file using the Nextion Editor with the provided HMI file.