Nextion Display am SVXLink

Antworten
DG7AA
FM-Funknetz Guru
Beiträge: 23
Registriert: Sa 9. Okt 2021, 11:27

Nextion Display am SVXLink

Beitrag von DG7AA »

+++++ Under Construction +++++ Keine Sorglos Anleitung +++++ Verwendung auf eigene Gefahr +++++ Kein Support +++++


Moin moin,

da ich von meinem DMR Hotspot noch zwei Nextion Displays liegen hatte, habe ich mich gefragt ob man die nicht auch am SVXLink betreiben kann. Da der Windet ja nun vor der Tür steht und das Wetter in den letzten Tage einfach nur schmuddelig war und mir Bast Sterne zu Weihnachten basteln auch nicht besonders liegt habe ich mich mit dem Thema einmal ausgiebig beschäftigt. Hier nun das Ergebnis:


Nex3.jpg
Nex3.jpg (206.09 KiB) 12431 mal betrachtet
2,4 Zoll Display am Raspi 1


Nex4.jpg
Nex4.jpg (213.83 KiB) 12431 mal betrachtet
3,5 Zoll Display am Raspi Zero W mit kleiner Powerbank im 3D Druck Gehäuse

Der Betrieb läuft abgesetzt, d.h. die Daten werden per Netzwerk übertragen. Somit kann das Display unabhängig vom Relais / Hotspot Standort betrieben werden.

Wie funktioniert das ganze? Da ich meine Relaisfunkstellen / Hotspots alle über einen VPN Server verbunden habe auf den die Raspis über SMB zugreifen können, sendet mir SVXLink aus der entsprechenden TCL Datei heraus einen Text in eine bestimmte Datei auf den VPN Server die der Display Raspi mit einem Python3 Script abfragt. Hier das Beispiel für den Zustand des TRX:

Code: Alles auswählen

#
# Executed each time the transmitter is turned on or off
#   is_on - Set to 1 if the transmitter is on or 0 if it's off
#
proc transmit {is_on} {
  #puts "Turning the transmitter $is_on";
  variable prev_ident;
  variable need_ident;
  if {$is_on && ([clock seconds] - $prev_ident > 5)} {
    set need_ident 1;
  }
  if {$is_on == 1} {
  exec echo "TX" > /var/log/display/tx;
  } else { exec echo "RX" > /var/log/display/tx
 }
}
Für das Display müssen wir uns eine entsprechende Oberfläche mit dem Nextion Editor bauen und die Textfelder entsprechend anlegen in die wir diese Werte später mit unserem Display Raspi dann reinschreiben wollen. Den Nextion Editor gibt es auf der Hersteller Seite unter:

https://nextion.tech/nextion-editor/

Auf dem Raspi habe ich Debian Bullseye installiert und Python3. Weiter braucht man noch die Nextion Python Sourcen von pypi:

https://pypi.org/project/nextion/

Dann habe ich mir ein Python3 Scribt gebaut mit dem ich die Daten auf dem Server abfrage und an das Display verschicke:

Code: Alles auswählen

#StartVariablen
tg = "StartUp"
lh = "None"
tx = "RX"
netz = "FM-Funknetz"
call = "DB0EIN-DV"
news = "+++++ no News +++++"
netz1 = "FM-Funknetz"
call1 = "DG7AA-HS"

import asyncio
import logging
import random
import sys
import time

from nextion import Nextion, EventType

class App:
    def __init__(self):
        self.client = Nextion('/dev/ttyS0', 9600, self.event_handler)
    
    # Note: async event_handler can be used only in versions 1.8.0+ (versions 1.8.0+ supports both sync and async versions)
    async def event_handler(self, type_, data):
        logging.info('Event %s data: %s', type, str(data))

    async def run(self):
        await self.client.connect()
        await self.client.command ('page FUNKNETZ')
    
        #await client.sleep()
        #await client.wakeup()
    
        while 1:
          page = (await self.client.command('sendme'))
          f = open("/sys/class/thermal/thermal_zone0/temp", "r")
          t = f.readline ()
          cputemp = t[0:2]
          unwetter = open("/var/log/display/DB0EIN-DV/unwetter", "r")
          unwetter1 = unwetter.readline()
          unwettero = open("/var/log/display/DB0EIN-DV/unwettero", "r")
          unwettero1 = unwettero.readline()
          wetter = open("/var/log/display/DB0EIN-DV/wetter", "r")
          wetter1 = wetter.readline()


          tg = open("/var/log/display/DB0EIN-DV/talkgroup", "r")
          atg = tg.readline()
          lh = open("/var/log/display/DB0EIN-DV/lh", "r")
          lh1 = lh.readline()
          tx = open("/var/log/display/DB0EIN-DV/tx", "r")
          tx1 = tx.readline()
          news1 = " +++ "+str(wetter1)+" +++ CPU Temperatur: "+str(cputemp)+" Grad +++ "+str(unwetter1)+" +++ "+str(unwettero1)+" +++ "
          zeit = (time.strftime("%d.%m.%Y  %H:%M"))+" Uhr"


          if "RX" in tx1 :
              c = 33808
          else:
              c = 63488

          await self.client.set('FUNKNETZ.tg.txt', str(atg))
          await self.client.set('FUNKNETZ.lh.txt', str(lh1))
          await self.client.set('FUNKNETZ.news.txt', str(news1))
          await self.client.set('FUNKNETZ.tx.pco', c)
          await self.client.set('FUNKNETZ.tx.txt', str(tx1))
          await self.client.set('FUNKNETZ.netz.txt', str(netz))
          await self.client.set('FUNKNETZ.call.txt', str(call))
          await self.client.set('FUNKNETZ.uhr.txt', str(zeit))


if __name__ == '__main__':
    logging.basicConfig(
        format='%(asctime)s - %(levelname)s - %(message)s',
        level=logging.INFO,
        handlers=[
            logging.StreamHandler()
        ])
    loop = asyncio.get_event_loop()
    app = App()
    asyncio.ensure_future(app.run())
    loop.run_forever()
Das Ergebnis seht ihr oben.

Aussichten und Ideen:

Da das Nextion Display über einen Touchscreen verfügt ist es auch möglich zwischen mehreren Oberflächen umzuschalten um z.B. mehrere Relais / Hotspots auszulesen. Das konnte ich inzwischen auch schon erfolgreich bei dem 2,4 Zoll Display testen. Bei meinen beiden 3,5 Zoll Displays ist der Touch leider kaputt. Mit dem Touchscreen könnte man auch auch Befehle an das Relais unter Umständen wieder zurück senden, z.B. an die "dtmf.pty", was ich bislang aber noch nicht probiert habe. Weiter ist es sicherlich auch möglich anstatt des wesentlich teureren und auch Energie intensiveren Raspi z.B. einen Wemos D1 Mini , wie ihn Jens für sein Display verwendet, einzusetzen. Erste Befehle an das Nextion mit dem Wemos zu senden waren bei mir ebenfalls erfolgreich. Es wäre auch denkbar Daten direkt von fm-funketz aus dem Dashboard oder aus dem SVXLink log auszulesen und darzustellen wie das z.B. der SVXCube macht.

Eine alternative zu den doch recht teuren Nextion Displays könnten die Displays von TJC sein die allerdings für den chinesischen Markt produziert werden. Diese sind auf den ersten Blick baugleich mit den Nextion und die Software dafür ist zu 100% identisch, außer das die TJC Software nur in chinesisch verfügbar ist. Da die Buttons aber identisch angeordnet sind kann man sich ja die englische Software zusätzlich aufmachen und dann 1 zu 1 die Buttons bedienen. Für 12,68€ das Stück habe ich mir deshalb mal 2 bei Ali bestellt und werde das mal testen.

** Ein kurzer Dank an Hans-Jürgen, DO4YNH der mir das Gehäuse gedruckt hat und mir den Tipp mit den TJC Displays gegeben hat. **

+++++ Under Construction +++++ Keine Sorglos Anleitung +++++ Verwendung auf eigene Gefahr +++++ Kein Support +++++
DG7AA - Autodidaktischer Hobbyfrickler
Sysop DB0EIN - www.db0ein.de
Cosysop DO0RDG - www.do0rdg.de
Cosysop DO0LF
DG7AA
FM-Funknetz Guru
Beiträge: 23
Registriert: Sa 9. Okt 2021, 11:27

Re: Nextion Display am SVXLink

Beitrag von DG7AA »

Hier ein Update. Mit Buttons auf dem Touchscreen:

Code: Alles auswählen

### SVXDisplay by DG7AA ###
### ****no warranty**** ###

#StartVariablen
tg = "StartUp"
lh = "None"
tx = "TX is Off"
netz = "FM-FUNKNETZ"
call = "DB0EIN-DV"
news = "+++++ no News +++++"
netz1 = "FM-FUNKNETZ"
call1 = "DG7AA-HS"

##define TG varibles
tg1 = "10"
tg2 = "77"
tg3 = "262"
tg4 = "2620"
tg5 = "34497"
tg6 = "37574"
tg7 = "56479"
tg8 = "9990"
tg9 = ""
tg10 = ""
tg11 = ""
tg12 = ""
tg13 = ""
tg14 = ""
tg15 = ""

##define CMD varaibles
Button1 = "Papagei"
cmd1 = "*99#"
Button2 = "Temp"
cmd2 = "*70#"
Button3 = "Wetter"
cmd3 = "*71#"
Button4 = "Unwetter1"
cmd4 = "*73#"
Button5 = "Unwetter2"
cmd5 = "*74#"
Button6 = ""
cmd6 = ""
Button7 = ""
cmd7 = ""
Button8 = ""
cmd8 = ""
cmd9 = "*54321#" #shutdown Pi
cmd10 = "" #stop svx
cmd11 = "" #start svx
cmd12 = "*54444#" #restart svx
Button13 = ""
cmd13 = ""
Button14 = ""
cmd14 = ""



import asyncio
import logging
import random
import sys
import time
import os

from nextion import Nextion, EventType

class App:
    def __init__(self):
        self.client = Nextion('/dev/ttyS0', 9600, self.event_handler)



    
    # Note: async event_handler can be used only in versions 1.8.0+ (versions 1.8.0+ supports both sync and async versions)
    async def event_handler(self, type_, data):

        await self.client.set('TOUCH1.call.txt', str(call))
        await self.client.set('TOUCH2.call.txt', str(call))


        ##define Buttons Page 3
        await self.client.set('TOUCH1.tg1.txt', str(tg1))
        await self.client.set('TOUCH1.tg2.txt', str(tg2))
        await self.client.set('TOUCH1.tg3.txt', str(tg3))
        await self.client.set('TOUCH1.tg4.txt', str(tg4))
        await self.client.set('TOUCH1.tg5.txt', str(tg5))
        await self.client.set('TOUCH1.tg6.txt', str(tg6))
        await self.client.set('TOUCH1.tg7.txt', str(tg7))
        await self.client.set('TOUCH1.tg8.txt', str(tg8))
        await self.client.set('TOUCH1.tg9.txt', str(tg9))
        await self.client.set('TOUCH1.tg10.txt', str(tg10))
        await self.client.set('TOUCH1.tg11.txt', str(tg11))
        await self.client.set('TOUCH1.tg12.txt', str(tg12))
        await self.client.set('TOUCH1.tg13.txt', str(tg13))
        await self.client.set('TOUCH1.tg14.txt', str(tg14))
        await self.client.set('TOUCH1.tg15.txt', str(tg15))

        ##define Buttons on Page 4
        await self.client.set('TOUCH2.cmd1.txt', str(Button1))
        await self.client.set('TOUCH2.cmd2.txt', str(Button2))
        await self.client.set('TOUCH2.cmd3.txt', str(Button3))
        await self.client.set('TOUCH2.cmd4.txt', str(Button4))
        await self.client.set('TOUCH2.cmd5.txt', str(Button5))
        await self.client.set('TOUCH2.cmd6.txt', str(Button6))
        await self.client.set('TOUCH2.cmd7.txt', str(Button7))
        await self.client.set('TOUCH2.cmd8.txt', str(Button8))
        await self.client.set('TOUCH2.cmd13.txt', str(Button13))
        await self.client.set('TOUCH2.cmd14.txt', str(Button14))




        if type_ == EventType.STARTUP:
            print('We have booted up!')
        elif type_ == EventType.TOUCH:
            print('A button (id: %d) was touched on page %d' % (data.component_id, data.page_id))
            touch=(str(data.page_id)+str(data.component_id))
            print (touch)

        ## Talkgroups on Page 3
        if touch == str(31):
             os.system("echo *91"+str(tg1)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(32):
             os.system("echo *91"+str(tg2)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(33):
             os.system("echo *91"+str(tg3)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(34):
             os.system("echo *91"+str(tg4)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(35):
             os.system("echo *91"+str(tg5)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(36):
             os.system("echo *91"+str(tg6)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(37):
             os.system("echo *91"+str(tg7)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(38):
             os.system("echo *91"+str(tg8)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(39):
             os.system("echo *91"+str(tg9)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(310):
             os.system("echo *91"+str(tg10)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(311):
             os.system("echo *91"+str(tg11)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(312):
             os.system("echo *91"+str(tg12)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(313):
             os.system("echo *91"+str(tg13)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(314):
             os.system("echo *91"+str(tg14)+"# > /home/pi/display/svxlink_disp_pty")
        elif touch == str(315):
             os.system("echo *91"+str(tg15)+"# > /home/pi/display/svxlink_disp_pty")

        ##commands on Page 4
        elif touch == str(41):
             os.system("echo "+str(cmd1)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(42):
             os.system("echo "+str(cmd2)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(43):
             os.system("echo "+str(cmd3)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(44):
             os.system("echo "+str(cmd4)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(45):
             os.system("echo "+str(cmd5)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(46):
             os.system("echo "+str(cmd6)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(47):
             os.system("echo "+str(cmd7)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(48):
             os.system("echo "+str(cmd8)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(49):
             os.system("echo "+str(cmd9)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(410):
             os.system("echo "+str(cmd10)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(411):
             os.system("echo "+str(cmd11)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(412):
             os.system("echo "+str(cmd12)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(413):
             os.system("echo "+str(cmd13)+" > /home/pi/display/svxlink_disp_pty")
        elif touch ==  str(414):
             os.system("echo "+str(cmd14)+" > /home/pi/display/svxlink_disp_pty")
        elif touch == str(415):
             os.system('sudo shutdown now')





        logging.info('Event %s data: %s', type, str(data))

    async def run(self):
        await self.client.connect()
        await self.client.command ('page DB0EINDV')
#        await self.client.command ('dim=100')


        #await client.sleep()
        #await client.wakeup()
    
        while 1:
          page = (await self.client.command('sendme'))
          f = open("/sys/class/thermal/thermal_zone0/temp", "r")
          t = f.readline ()
          cputemp = t[0:2]
          unwetter = open("/var/log/display/DB0EIN-DV/unwetter", "r")
          unwetter1 = unwetter.readline()
          unwettero = open("/var/log/display/DB0EIN-DV/unwettero", "r")
          unwettero1 = unwettero.readline()
          wetter = open("/var/log/display/DB0EIN-DV/wetter", "r")
          wetter1 = wetter.readline()


          if page == 1:

           tg = open("/var/log/display/DB0EIN-DV/talkgroup", "r")
           atg = tg.readline()
           lh = open("/var/log/display/DB0EIN-DV/lh", "r")
           lh1 = lh.readline()
           tx = open("/var/log/display/DB0EIN-DV/tx", "r")
           tx1 = tx.readline()
           news1 = " +++ "+str(wetter1)+" +++ CPU Temperatur: "+str(cputemp)+" Grad +++ "+str(unwetter1)+" +++ "+str(unwettero1)+" +++ "
           zeit = (time.strftime("%d.%m.%Y  %H:%M"))+" Uhr"


           if "RX" in tx1 :
              c = 33808
           else:
              c = 63488

           await self.client.set('DB0EINDV.tg.txt', str(atg))
           await self.client.set('DB0EINDV.lh.txt', str(lh1))
           await self.client.set('DB0EINDV.news.txt', str(news1))
           await self.client.set('DB0EINDV.tx.pco', c)
           await self.client.set('DB0EINDV.tx.txt', str(tx1))
           await self.client.set('DB0EINDV.netz.txt', str(netz))
           await self.client.set('DB0EINDV.call.txt', str(call))
           await self.client.set('DB0EINDV.uhr.txt', str(zeit))

          else:

           tg2 = open("/var/log/display/DG7AA-HS/talkgroup", "r")
           atg2 = tg2.readline()
           lh2 = open("/var/log/display/DG7AA-HS/lh", "r")
           lh3 = lh2.readline()
           tx2 = open("/var/log/display/DG7AA-HS/tx", "r")
           tx3 = tx2.readline()
           news1 = " +++ "+str(wetter1)+" +++ CPU Temperatur: "+str(cputemp)+" Grad +++ "+str(unwetter1)+" +++ "+str(unwettero1)+" +++ "
           zeit = (time.strftime("%d.%m.%Y  %H:%M"))+" Uhr"


           if "RX" in tx3 :
               c = 33808
           else:
               c = 63488

           await self.client.set('DG7AAHS.tg.txt', str(atg2))
           await self.client.set('DG7AAHS.lh.txt', str(lh3))
           await self.client.set('DG7AAHS.tx.pco', c)
           await self.client.set('DG7AAHS.tx.txt', str(tx3))
           await self.client.set('DG7AAHS.netz.txt', str(netz))
           await self.client.set('DG7AAHS.call.txt', str(call1))
           await self.client.set('DG7AAHS.news.txt', str(news1))
           await self.client.set('DG7AAHS.uhr.txt', str(zeit))


if __name__ == '__main__':
    logging.basicConfig(
        format='%(asctime)s - %(levelname)s - %(message)s',
        level=logging.INFO,
        handlers=[
            logging.StreamHandler()
        ])
    loop = asyncio.get_event_loop()
    app = App()
    asyncio.ensure_future(app.run())
    loop.run_forever()
    
DG7AA - Autodidaktischer Hobbyfrickler
Sysop DB0EIN - www.db0ein.de
Cosysop DO0RDG - www.do0rdg.de
Cosysop DO0LF
Antworten