Elektronisches Preisschild Sammelbestellung - Ansteuerung
Moderatoren: Sven, TDI, Heaterman, Finger, duese, Marsupilami72
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Hat denn schon jemand was gebastelt um die Teile per ZigBee2MQTT anzusprechen?
Einen CC2531 habe ich (noch) nicht da, aber einen CC1352 inkl. ZigBee Firmware. Das muss doch auch irgendwie gehen.
Einen CC2531 habe ich (noch) nicht da, aber einen CC1352 inkl. ZigBee Firmware. Das muss doch auch irgendwie gehen.
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Probier doch einfach mal das Zigbee2Mqtt auf Anlernen zu schalten und das Schild (Batterien raus, Batterien rein) dann ganz ganz dicht neben die Antenne zu packen und das Logfile zu beobachten ob da irgendwas kommt.
Ich bin mir aber nicht sicher ob zigbee2mqtt überhaupt eine Funktion hat um Nutzdaten (das Bild) zu übertragen. Das war ursprünglich gedacht um Sensordaten zu empfangen.
Bei ganz wenigen wird auch was gesendet: https://www.zigbee2mqtt.io/devices/mTouch_One.html
Da gäbe es dann display_text , dafür müsste das Schild dann vermutlich eine andere Firmware haben die aus zugesandtem Text ein Bild rendert.
Ich bin mir aber nicht sicher ob zigbee2mqtt überhaupt eine Funktion hat um Nutzdaten (das Bild) zu übertragen. Das war ursprünglich gedacht um Sensordaten zu empfangen.
Bei ganz wenigen wird auch was gesendet: https://www.zigbee2mqtt.io/devices/mTouch_One.html
Da gäbe es dann display_text , dafür müsste das Schild dann vermutlich eine andere Firmware haben die aus zugesandtem Text ein Bild rendert.
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Tja, wenn das so einfach wäre...
Also Pairing passiert nicht, selbst im Debug Modus passiert nichts. Ich sehe aber, dass ein Paket (eigentlich zwei) vom Display gesendet wird, dann aber bereits vom Zigbee Stack verworfen wird, weil es kein gültiges ZigBee Paket sei. Das heißt das Paket geht gar nichts bis zum Rechner und ZigBee2MQTT.
Wenn ich mir die station.py anschauen, sieht mir das aber so aus, als ob die ganze Kommunikation verschlüsselt ist, auch das Pairing?! Hier steige ich aber noch nicht durch wie ich das ZigBee2MQTT klar machen soll. Ein
führt auch nicht zu Funktion.
Also Pairing passiert nicht, selbst im Debug Modus passiert nichts. Ich sehe aber, dass ein Paket (eigentlich zwei) vom Display gesendet wird, dann aber bereits vom Zigbee Stack verworfen wird, weil es kein gültiges ZigBee Paket sei. Das heißt das Paket geht gar nichts bis zum Rechner und ZigBee2MQTT.
Wenn ich mir die station.py anschauen, sieht mir das aber so aus, als ob die ganze Kommunikation verschlüsselt ist, auch das Pairing?! Hier steige ich aber noch nicht durch wie ich das ZigBee2MQTT klar machen soll. Ein
Code: Alles auswählen
network_key: [ 0xD3,0x06,0xD9,0x34,0x8E, 0x29, 0xE5, 0xE3, 0x58, 0xBF, 0x29, 0x34, 0x81, 0x20, 0x02, 0xC1 ]
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Das Preisschild läuft definitiv nur mit dem Stick auf dem die TiMac Firmware drauf ist.
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Also kein ZigBee, sondern nur sowas ähnliches auf 802.15.4 basierend? Schade...
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Ich hab da mal was messen lassen:Andreas_P hat geschrieben: ↑Do 27. Okt 2022, 19:42 Zum Flashen der Preisschilder möchte ich mir einen Stecker drucken den ich auf die Kontakteinflächen der Preisschilder drauf halte,
dazu fehlt mir die Info in welchen Abstand die einzelnen Kontaktflächen zu einander haben. Hat dazu jemand Informationen ?

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Das lässt mir ja doch keine Ruhe... Ich habe jetzt einen 802.15.4 Stack am laufen und bekomme auch Daten, jetzt möchte ich aber nicht den ganzen TIMAC reverse engineeren. Kann mir jemand die Ausgabe die beim ersten pairen von station.py --l --d ausgegeben wird senden?
Idealerweise noch print("pkt", pkt.hex()) am Anfang der def process_pkt(pkt): Funktion einfügen.
Sollte dann so irgendwie aussehen:
Hintergrund: TIMAC sendet irgendwie wohl keinen Header, ich habe aber einen, daher würde ich gerne die Unterschiede sehen. Irgendwie dürfte ein CC1352 mit ordentlicher Antenne auch etwas besser sein.
Idealerweise noch print("pkt", pkt.hex()) am Anfang der def process_pkt(pkt): Funktion einfügen.
Sollte dann so irgendwie aussehen:
Code: Alles auswählen
python3 station.py --l --d
DISCOVER-MODE
Labermodus
2022-11-04 19:41:59,818 pkt 1f3b10c36c0200000300ffff0000000000000200fe54a90035004744ffff7000c500000000000000ff00000000000000000000000000000000000000585600202f000000ffffffff975f0100e4550020dfdf000080350020e12f01000000
2022-11-04 19:41:59,821 data 00000000000000000000000000585600202f000000ffffffff975f0100e4550020dfdf000080350020e12f01000000
2022-11-04 19:41:59,821 hdr 41cc00ff7000000000000200fe6c0200000300ffff
2022-11-04 19:41:59,821 ciph 00000000000000000000000000585600202f000000ffffffff975f0100e4550020dfdf00008035
2022-11-04 19:41:59,821 nonce 010000006c0200000300ffff00
2022-11-04 19:41:59,822 tag 0020e12f
2022-11-04 19:41:59,822 packet is NOT authentic
- ProgBernie
- Beiträge: 298
- Registriert: Fr 16. Sep 2022, 21:59
- Wohnort: Zwischen Hamburg und Haiti ^W Lübeck
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Ich habe station.py wie folgt abgeändert:
Damit erhalte ich bei einem reset des Schildes:
Code: Alles auswählen
def process_pkt(pkt):
if laber:
print("pkt", pkt)
print("pkt['data']", pkt['data'].hex())
Code: Alles auswählen
pi@TEApi:~/estation $ python station.py --l --d
DISCOVER-MODE
Labermodus
2022-11-04 21:20:54,113 Station started
2022-11-04 21:23:43,993 pkt {'type': 'parse_mac_data_ind', 'src_add_mode': 3, 'src_add': [0, 0, 2, 109, 108, 153, 59, 26], 'dst_add_mode': 2, 'dst_add': b'\xff\xff', 'timestamp': b';\x1a\x08\x00', 'timestamp2': b'\xb2\x04', 'src_pan_id': b'GD', 'dst_pan_id': b'\xff\xff', 'link_quality': 89, 'correlation': 107, 'rssi': 203, 'dsn': 0, 'key_source': b'\x00\x00\x00\x00\x00\x00\x00\x00', 'security_level': 0, 'key_id_mode': 0, 'key_index': 0, 'length': 47, 'data': b'\xcd\xd6\x94\t\x1c+9\x14\xb1h\xa1O^\xa9?\x02U\xfd)\xcd\xc0\x08\x03PC\xafR\xc0*E\x19\x08\xfcV\xaf\xd1\xffHBp\xc2\xc8T\x00\x00\x00\x00'}
2022-11-04 21:23:43,995 pkt['data'] cdd694091c2b3914b168a14f5ea93f0255fd29cdc008035043af52c02a451908fc56afd1ff484270c2c85400000000
2022-11-04 21:23:44,028 rcvd_packet: f00000000000130100000800280a00800028011d0043000200c800100000000000000000000000
2022-11-04 21:23:44,029 rcvhdr: 01c800ffffffff47441a3b996c6d020000
2022-11-04 21:23:44,036 Got assoc request
2022-11-04 21:23:44,037 TagInfo(protoVer=0, swVer=1181116006400, hwType=8, batteryMv=2600, rfu1=0, screenPixWidth=128, screenPixHeight=296, screenMmWidth=29, screenMmHeight=67, compressionsSupported=2, maxWaitMsec=200, screenType=16, rfu=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
2022-11-04 21:23:44,038 AssocInfo(checkinDelay=900000, retryDelay=1000, failedCheckinsTillBlank=2, failedCheckinsTillDissoc=2, newKey=bytearray(b'\xd3\x06\xd94\x8e)\xe5\xe3X\xbf)4\x81 \x02\xc1'), rfu=bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00'))
2022-11-04 21:23:44,038 hdr: 41cc0147441a3b996c6d0200003549d914004b1200
2022-11-04 21:23:44,039 nonce: d07465633549d914004b120000
2022-11-04 21:24:10,325 pkt {'type': 'parse_mac_data_ind', 'src_add_mode': 3, 'src_add': [0, 0, 2, 109, 108, 153, 59, 26], 'dst_add_mode': 3, 'dst_add': b'5I\xd9\x14\x00K\x12\x00', 'timestamp': b'\xa9[\t\x00', 'timestamp2': b'\x01%', 'src_pan_id': b'GD', 'dst_pan_id': b'GD', 'link_quality': 89, 'correlation': 107, 'rssi': 203, 'dsn': 0, 'key_source': b"\x08\x00'\x1e\x00\x1a;\x99", 'security_level': 0, 'key_id_mode': 63, 'key_index': 0, 'length': 30, 'data': b'\xcf\xd6\x94\t\x1c8+\x15\xb1`\xa9\xb9\x7f\xa3?\x1aU\xd5(\xd0\xc0K\xfeK\x16E\x00\x00\x00\x00'}
2022-11-04 21:24:10,326 pkt['data'] cfd694091c382b15b160a9b97fa33f1a55d528d0c04bfe4b164500000000
2022-11-04 21:24:10,329 rcvd_packet: f200000000130100000800f609000098000000000000
2022-11-04 21:24:10,329 rcvhdr: 41cc0047443549d914004b12001a3b996c6d020000
2022-11-04 21:24:10,331 Got checkin request
2022-11-04 21:24:10,332 CheckinInfo(swVer=1181116006400, hwType=8, batteryMv=2550, lastPacketLQI=0, lastPacketRSSI=0, temperature=152, rfu=b'\x00\x00\x00\x00\x00\x00')
2022-11-04 21:24:10,333 Reading image file:./0000026d6c993b1a.bmp/.png
2022-11-04 21:24:10,334 Using ./0000026d6c993b1a.png file
2022-11-04 21:24:10,335 Reading firmware file: UPDT0008.BIN
2022-11-04 21:24:10,336 No Firmware file available
2022-11-04 21:24:10,337 PendingInfo(imgUpdateVer=7161838112113685969, imgUpdateSize=9542, osUpdateVer=0, osUpdateSize=0, nextCheckinDelay=0, rfu=bytearray(b'\x00\x00\x00\x00'))
2022-11-04 21:24:10,338 hdr: 41cc0247441a3b996c6d0200003549d914004b1200
2022-11-04 21:24:10,338 nonce: ea7465633549d914004b120000
2022-11-04 21:24:10,554 pkt {'type': 'parse_mac_data_ind', 'src_add_mode': 3, 'src_add': [0, 0, 2, 109, 108, 153, 59, 26], 'dst_add_mode': 3, 'dst_add': b'5I\xd9\x14\x00K\x12\x00', 'timestamp': b'u^\t\x00', 'timestamp2': b'\xb4\x16', 'src_pan_id': b'GD', 'dst_pan_id': b'GD', 'link_quality': 89, 'correlation': 107, 'rssi': 203, 'dsn': 1, 'key_source': b'\t\x00j\x06\x00\x00K\x12', 'security_level': 0, 'key_id_mode': 59, 'key_index': 0, 'length': 29, 'data': b'd4T\x0eGD\x8e\xab\x16P5\x07q\x8e$\xcf\xee\x83\xab\x9ex\x1c\xd0\xf9v\x01\x00\x00\x00'}
2022-11-04 21:24:10,555 pkt['data'] 6434540e47448eab16503507718e24cfee83ab9e781cd0f97601000000
2022-11-04 21:24:10,558 rcvd_packet: f4d1f56363d1f56363000000005800000000000000
2022-11-04 21:24:10,559 rcvhdr: 41cc0147443549d914004b12001a3b996c6d020000
2022-11-04 21:24:10,560 Got chunk request
2022-11-04 21:24:10,561 ChunkReqInfo(versionRequested=7161838112113685969, offset=0, len=88, osUpdatePlz=0, rfu=b'\x00\x00\x00\x00\x00\x00')
2022-11-04 21:24:10,562 ChunkInfo(offset=0, osUpdatePlz=0, rfu=0)
2022-11-04 21:24:10,563 Reading image file: /tmp/0000026D6C993B1A_7161838112113685969.bmp
2022-11-04 21:24:10,567 sending chunk 95 f5000000000000424d46 ...
2022-11-04 21:24:10,568 hdr: 41cc0347441a3b996c6d0200003549d914004b1200
2022-11-04 21:24:10,569 nonce: ea7465633549d914004b120000
2022-11-04 21:24:10,659 pkt {'type': 'parse_mac_data_ind', 'src_add_mode': 3, 'src_add': [0, 0, 2, 109, 108, 153, 59, 26], 'dst_add_mode': 3, 'dst_add': b'5I\xd9\x14\x00K\x12\x00', 'timestamp': b'\xc1_\t\x00', 'timestamp2': b'\x9f%', 'src_pan_id': b'GD', 'dst_pan_id': b'GD', 'link_quality': 89, 'correlation': 107, 'rssi': 203, 'dsn': 2, 'key_source': b'\t\x00?\x1d\x00\x9e;\xcd', 'security_level': 0, 'key_id_mode': 121, 'key_index': 0, 'length': 29, 'data': b'z\xb2\xeb\xdd`\x1b.\xfco\xcd\x00\xbfM\xd1\xa5|\xc67\x837\xc1\rI\xbf\x81\x02\x00\x00\x00'}
2022-11-04 21:24:10,660 pkt['data'] 7ab2ebdd601b2efc6fcd00bf4dd1a57cc6378337c10d49bf8102000000
2022-11-04 21:24:10,662 rcvd_packet: f4d1f56363d1f56363580000005800000000000000
2022-11-04 21:24:10,663 rcvhdr: 41cc0247443549d914004b12001a3b996c6d020000
2022-11-04 21:24:10,665 Got chunk request
2022-11-04 21:24:10,665 ChunkReqInfo(versionRequested=7161838112113685969, offset=88, len=88, osUpdatePlz=0, rfu=b'\x00\x00\x00\x00\x00\x00')
2022-11-04 21:24:10,666 ChunkInfo(offset=88, osUpdatePlz=0, rfu=0)
2022-11-04 21:24:10,666 Reading image file: /tmp/0000026D6C993B1A_7161838112113685969.bmp
2022-11-04 21:24:10,667 sending chunk 95 f5580000000000555555 ...
2022-11-04 21:24:10,668 hdr: 41cc0447441a3b996c6d0200003549d914004b1200
2022-11-04 21:24:10,668 nonce: ea7465633549d914004b120000
2022-11-04 21:24:10,760 pkt {'type': 'parse_mac_data_ind', 'src_add_mode': 3, 'src_add': [0, 0, 2, 109, 108, 153, 59, 26], 'dst_add_mode': 3, 'dst_add': b'5I\xd9\x14\x00K\x12\x00', 'timestamp': b'\xf9`\t\x00', 'timestamp2': b"\xea'", 'src_pan_id': b'GD', 'dst_pan_id': b'GD', 'link_quality': 86, 'correlation': 107, 'rssi': 202, 'dsn': 3, 'key_source': b'\t\x00?\x07\x00\x9e;\xcd', 'security_level': 0, 'key_id_mode': 121, 'key_index': 0, 'length': 29, 'data': b'z\x11\x17"\xb8\xfeN#j\xcc"\xc41\xf0[\x95\x15\x8a!\x16~\x9b\xcc\xd2\xfc\x03\x00\x00\x00'}
2022-11-04 21:24:10,761 pkt['data'] 7a111722b8fe4e236acc22c431f05b95158a21167e9bccd2fc03000000
2022-11-04 21:24:10,763 rcvd_packet: f4d1f56363d1f56363b00000005800000000000000
2022-11-04 21:24:10,764 rcvhdr: 41cc0347443549d914004b12001a3b996c6d020000
2022-11-04 21:24:10,765 Got chunk request
2022-11-04 21:24:10,766 ChunkReqInfo(versionRequested=7161838112113685969, offset=176, len=88, osUpdatePlz=0, rfu=b'\x00\x00\x00\x00\x00\x00')
2022-11-04 21:24:10,767 ChunkInfo(offset=176, osUpdatePlz=0, rfu=0)
2022-11-04 21:24:10,767 Reading image file: /tmp/0000026D6C993B1A_7161838112113685969.bmp
2022-11-04 21:24:10,768 sending chunk 95 f5b00000000000555555 ...
2022-11-04 21:24:10,769 hdr: 41cc0547441a3b996c6d0200003549d914004b1200
2022-11-04 21:24:10,770 nonce: ea7465633549d914004b120000
...
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Danke, das muss ich in Ruhe verdauen. Da sind Ähnlichkeiten und Unterschiede...
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Die Info hat geholfen, dass die Pakete vom PC nun richtig empfangen werden. Das Beantworten passt noch nicht so ganz, da muss ich mir einen zweiten CC1352 besorgen, um mit zuschneiden was wirklich gesendet wird. Bisher ignoriert das Display leider die Antwort vom PC.
- ProgBernie
- Beiträge: 298
- Registriert: Fr 16. Sep 2022, 21:59
- Wohnort: Zwischen Hamburg und Haiti ^W Lübeck
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Wenn es Dir hilft kann ich einen gesamten Upload und die hochgeladene Bilddatei zur Verfügung stellen.
Ach ja: Unter 2.5V meldet sich das Display noch mit einem Assoc Request, aber bleibt dann stehen. Ob es die Antwort nicht mehr liest oder was da schief läuft weiß ich nicht, es bleibt jedenfalls mit ASSOCIATE READY im Display stehen. Batterien raus/rein lässt das ganze wieder erneut starten.
Ach ja: Unter 2.5V meldet sich das Display noch mit einem Assoc Request, aber bleibt dann stehen. Ob es die Antwort nicht mehr liest oder was da schief läuft weiß ich nicht, es bleibt jedenfalls mit ASSOCIATE READY im Display stehen. Batterien raus/rein lässt das ganze wieder erneut starten.
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Der Ausschnitt reicht erstmal, danke. Der Hinweis mit den 2,5 V ist gut, das Display bekommt hier aber externe 3.3 V, daher schließe ich das momentan noch aus,
Laut UART Ausgabe wird nach dem Senden schlafen gegangen.
Vielleicht sollte ich einfach auf den bestellten passenden CC Stick warten, dann lässt sich das einfacher umbauen.
Laut UART Ausgabe wird nach dem Senden schlafen gegangen.
Code: Alles auswählen
booted at 0x1aec Reset reason: 00
Booting FW ver 0x0000011300000000
-> FW v1.19.0.0
MAC 00:00:02:6C:C3:10:3B:1F
temp: 20
eeprom has 59 image slots
Erz IMAGES
Erz UPD
Erz SETTINGS
MESSAGE 'BOOTING'
booted at 0x1aec Reset reason: 01
Booting FW ver 0x0000011300000000
-> FW v1.19.0.0
MAC 00:00:02:6C:C3:10:3B:1F
temp: 20
eeprom has 59 image slots
Associate is displayed
MESSAGE 'ASSOCIATE READY'
booted at 0x1aec Reset reason: 01
Booting FW ver 0x0000011300000000
-> FW v1.19.0.0
MAC 00:00:02:6C:C3:10:3B:1F
temp: 21
eeprom has 59 image slots
Associate is not displayed
try ch 11
sleep: 791015
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Der Sourcecode der Displaysoftware hilft da wohl nicht weiter? Da müsste doch grob drinstehen, was das Funkmodul hören will. Übersehe ich etwas?
https://github.com/atc1441/E-Paper_Pricetags
https://github.com/atc1441/E-Paper_Pricetags
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Ja doch schon. Wenn ich das richtig verstanden haben sollte das so ablaufen:
Wie gesagt, ich warte einfach bis der Stick da ist, dann sollte sich das ganz einfach lösen lassen.
Code: Alles auswählen
- ...
- ASSOCIATE READY anzeigen
- 4x Kommunikationsversuch
- Nachricht senden
- Delay
- Empfang auswerten
- Wenn was sinnvolles, pairing fortsetzen, ...
- Ansonsten zumindest irgendwelche Meldungen
- nochmal
- Schlafen gehen
- ...
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Außen Temperaturanzeige aus der Influxdb gesaugt.
- ProgBernie
- Beiträge: 298
- Registriert: Fr 16. Sep 2022, 21:59
- Wohnort: Zwischen Hamburg und Haiti ^W Lübeck
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Ich denke es sind nicht die 2.5V, aber die Displays die beim Booten nur noch 2.5V zeigen laden hier kein Bild mehr, die Zellen sind wohl zu hochohmig. Beim Laden der Bild-Chunks werden am Labornetzteil 40mA gezogen, das wird gemittelt sein und der Funkkram zieht ordentlich Strom. Das Umschalten der Displays zieht nur etwa 2mA.
- ProgBernie
- Beiträge: 298
- Registriert: Fr 16. Sep 2022, 21:59
- Wohnort: Zwischen Hamburg und Haiti ^W Lübeck
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Aaron bietet uns Adaperplatinen für das direkte Ansteuern über Arduino an.
Stückpreis 5Euro.
https://www.pcbway.com/project/sharepro ... a845c.html
Seine Email Adresse zum bestellen:
adapter@43u.de
Stückpreis 5Euro.
https://www.pcbway.com/project/sharepro ... a845c.html
Seine Email Adresse zum bestellen:
adapter@43u.de
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Das Reichweitenproblem kann man erschlagen mit einem Stick, der eine SMA-Buchse hat und eine externe Antenne:
https://de.aliexpress.com/item/40006400 ... pt=glo2deu
Damit komme ich durch das ganze Haus.
https://de.aliexpress.com/item/40006400 ... pt=glo2deu
Damit komme ich durch das ganze Haus.
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Mit dem CC1352 bin ich noch nicht weitergekommen, da mein CC1352 einfach nichts zu senden scheint, also auch mit anderem CC1352 als Empfänger und TI SmartRF Studio getestet. Diese Baustelle muss aber erstmals ruhen.
In der Zwischenzeit habe ich etwas gebastelt, das anzeigt, welche Mülltonne rausgestellt werden muss. Jeweils am Tag vor der Abholung erscheint eine Meldung: Dazu müssen die Abholtermine als Kalenderdatei in abfuhrtermine.ics gespeichert sein und das Skript regelmässig (z.B. per Cron) aufgerufen werden. Die in destination_file konfigurierte Datei wird dann entsprechend aktualisiert.
In der Zwischenzeit habe ich etwas gebastelt, das anzeigt, welche Mülltonne rausgestellt werden muss. Jeweils am Tag vor der Abholung erscheint eine Meldung: Dazu müssen die Abholtermine als Kalenderdatei in abfuhrtermine.ics gespeichert sein und das Skript regelmässig (z.B. per Cron) aufgerufen werden. Die in destination_file konfigurierte Datei wird dann entsprechend aktualisiert.
Code: Alles auswählen
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Nov 12 12:18:43 2022
@author: omega
"""
# imports
from icalendar import Calendar, Event, vCalAddress, vText
from datetime import datetime, timedelta, time
from PIL import Image, ImageDraw, ImageFont
from pathlib import Path
from collections import namedtuple
import os
import pytz
import time
# init the calendar
cal = Calendar()
Display_Size_x=296
Display_Size_y=128
destination_file = '../epaper-station/0000023902443b13.png'
def generate_abhol_image(summary, datum):
muster=Image.new("RGB",(296,128),color=(255,255,255))
named_tuple = time.localtime() # get struct_time
time_string = time.strftime("%d.%m.%Y, %H:%M:%S", named_tuple)
im = ImageDraw.Draw(muster)
font = ImageFont.load('VeraMono30.pil')
font_klein = ImageFont.load('VeraMono8.pil')
_, _, w, h = im.textbbox((0, 0), summary, font=font)
im.text((((Display_Size_x/2)-w/2),Display_Size_y/2-h/2-30), summary ,fill=(0, 0, 0),font=font)
_, _, w, h = im.textbbox((0, 0), datum, font=font_klein)
im.text((((Display_Size_x/2)-w/2),80), datum ,fill=(0, 0, 0),font=font_klein)
_, _, w, h = im.textbbox((0, 0), time_string, font=font_klein)
im.text((((Display_Size_x/2)-w/2),100), time_string ,fill=(0, 0, 0),font=font_klein)
muster=muster.rotate(angle=90,expand="true")
muster.save(destination_file)
def generate_empty_image():
muster=Image.new("RGB",(296,128),color=(255,255,255))
named_tuple = time.localtime() # get struct_time
time_string = time.strftime("%d.%m.%Y, %H:%M:%S", named_tuple)
im = ImageDraw.Draw(muster)
font_klein = ImageFont.load('VeraMono8.pil')
_, _, w, h = im.textbbox((0, 0), time_string, font=font_klein)
im.text((((Display_Size_x/2)-w/2),100), time_string ,fill=(0, 0, 0),font=font_klein)
muster=muster.rotate(angle=90,expand="true")
muster.save(destination_file)
generate_empty_image()
today = datetime.today().date()
e = open('abfuhrtermine.ics', 'rb')
ecal = cal.from_ical(e.read())
for component in ecal.walk():
#print(component.name)
if component.name == "VEVENT":
#print (component.get('summary'))
#print (component.get('dtstart').dt)
nachrichttag = component.get('dtstart').dt - timedelta(days=1)
if(today==nachrichttag):
#print (component.get('summary'))
#print (component.get('dtstart').dt)
generate_abhol_image(str(component.get('summary')), str(component.get('dtstart').dt))
e.close()
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Ich hab jetzt meine PriceTags auch endlich angesteuert bekommen,
Aktuell erstelle ich noch meine PNG Dateien mit Paint.
Mich würde nur mal interessieren wie ich denn die rote Farbe vom Preisschild ansteuern kann?
Ist das ein definierter Rot-Farbton?
Gruss Thomas
Aktuell erstelle ich noch meine PNG Dateien mit Paint.
Mich würde nur mal interessieren wie ich denn die rote Farbe vom Preisschild ansteuern kann?
Ist das ein definierter Rot-Farbton?
Gruss Thomas
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Rot halt. In RGB: 255,0,0 bzw 100%,0%,0%
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
hm, also wenn ich rot (255,0,0) verwende im PNG bleibt es leider grau.
Ich hatte hier gelesen das es mit der station.py von Hightech gehen soll, die Variante die ich hier gefunden habe bringt mir leider einen Fehler beim Start.
Ich nutze das pyhton aktuell noch unter Windows.
Ausgabe station.py von Hightech: (die die ich hier irgendwo gefunden habe)
Meine aktuelle station.py ohne rot:
kann mir jemand weiterhelfen?
Ich hatte hier gelesen das es mit der station.py von Hightech gehen soll, die Variante die ich hier gefunden habe bringt mir leider einen Fehler beim Start.
Ich nutze das pyhton aktuell noch unter Windows.
Ausgabe station.py von Hightech: (die die ich hier irgendwo gefunden habe)
Code: Alles auswählen
import timaccop
import bmp2grays
from Cryptodome.Cipher import AES
from collections import namedtuple
import struct
import os, sys
import logging
from PIL import Image, ImageDraw, ImageFont
import time
parameter=sys.argv
discover=False
laber=False
if "--d" in parameter:
discover=True
print ("DISCOVER-MODE")
if "--l" in parameter:
discover=True
print ("Labermodus")
Display_Size_x=296
Display_Size_y=128
masterkey = bytearray.fromhex("D306D9348E29E5E358BF2934812002C1")
PORT = com4("EPS_PORT", default="/dev/ttyACM0")
EXTENDED_ADDRESS = [ int(addr.strip(), 16) for addr in os.environ.get("EPS_EXTENDED_ADDRESS", default="0x00, 0x12, 0x4B, 0x00, 0x14, 0xD9, 0x49, 0x35").split(",") ]
PANID = [ int(panid.strip(), 16) for panid in os.environ.get("EPS_PANID", default="0x47, 0x44").split(",") ]
CHANNEL = int(os.environ.get("EPS_CHANNEL", default="11"))
IMAGE_DIR = os.environ.get("EPS_IMAGE_DIR", default="./")
IMAGE_WORKDIR = os.environ.get("EPS_IMAGE_WORKDIR", default="/tmp/")
CHECKIN_DELAY = int(os.environ.get("EPS_CHECKIN_DELAY", default="900000")) # 900s
RETRY_DELAY = int(os.environ.get("EPS_RETRY_DELAY", default="1000")) # 1s
FAILED_CHECKINS_TILL_BLANK = int(os.environ.get("EPS_FAILED_CHECKINS_TILL_BLANK", default="2"))
FAILED_CHECKINS_TILL_DISSOC = int(os.environ.get("EPS_FAILED_CHECKINS_TILL_DISSOC", default="2"))
PKT_ASSOC_REQ = (0xF0)
PKT_ASSOC_RESP = (0xF1)
PKT_CHECKIN = (0xF2)
PKT_CHECKOUT = (0xF3)
PKT_CHUNK_REQ = (0xF4)
PKT_CHUNK_RESP = (0xF5)
VERSION_SIGNIFICANT_MASK = (0x0000ffffffffffff)
HW_TYPE_42_INCH_SAMSUNG = (1)
HW_TYPE_42_INCH_SAMSUNG_ROM_VER_OFST = (0xEFF8)
HW_TYPE_74_INCH_DISPDATA = (2)
HW_TYPE_74_INCH_DISPDATA_FRAME_MODE = (3)
HW_TYPE_74_INCH_DISPDATA_ROM_VER_OFST = (0x008b)
HW_TYPE_ZBD_EPOP50 = (4)
HW_TYPE_ZBD_EPOP50_ROM_VER_OFST = (0x008b)
HW_TYPE_ZBD_EPOP900 = (5)
HW_TYPE_ZBD_EPOP900_ROM_VER_OFST = (0x008b)
HW_TYPE_29_INCH_DISPDATA = (6)
HW_TYPE_29_INCH_DISPDATA_FRAME_MODE = (7)
HW_TYPE_29_INCH_DISPDATA_ROM_VER_OFST = (0x008b)
HW_TYPE_29_INCH_ZBS_026 = (8)
HW_TYPE_29_INCH_ZBS_026_FRAME_MODE = (9)
HW_TYPE_29_INCH_ZBS_025 = (10)
HW_TYPE_29_INCH_ZBS_025_FRAME_MODE = (11)
HW_TYPE_154_INCH_ZBS_033 = (18)
HW_TYPE_154_INCH_ZBS_033_FRAME_MODE = (19)
HW_TYPE_42_INCH_ZBS_026 = (28)
HW_TYPE_42_INCH_ZBS_026_FRAME_MODE = (29)
HW_TYPE_29_INCH_ZBS_ROM_VER_OFST = (0x008b)
TagInfo = namedtuple('TagInfo', """
protoVer,
swVer,
hwType,
batteryMv,
rfu1,
screenPixWidth,
screenPixHeight,
screenMmWidth,
screenMmHeight,
compressionsSupported,
maxWaitMsec,
screenType,
rfu
""")
AssocInfo = namedtuple('AssocInfo', """
checkinDelay,
retryDelay,
failedCheckinsTillBlank,
failedCheckinsTillDissoc,
newKey,
rfu
""")
CheckinInfo = namedtuple('CheckinInfo', """
swVer,
hwType,
batteryMv,
lastPacketLQI,
lastPacketRSSI,
temperature,
rfu,
""")
PendingInfo = namedtuple('PendingInfo', """
imgUpdateVer,
imgUpdateSize,
osUpdateVer,
osUpdateSize,
nextCheckinDelay,
rfu
""")
ChunkReqInfo = namedtuple('ChunkReqInfo', """
versionRequested,
offset,
len,
osUpdatePlz,
rfu,
""")
ChunkInfo = namedtuple('ChunkInfo', """
offset,
osUpdatePlz,
rfu,
""")
logging.basicConfig(format='%(asctime)s %(message)s')
logger = logging.getLogger(__name__)
dsn = 0
def print(*args):
msg = ""
for arg in args:
msg += str(arg) + " "
logger.warning(msg)
def decrypt(hdr, enc, tag, nonce):
cipher = AES.new(masterkey, AES.MODE_CCM, nonce, mac_len=4)
cipher.update(hdr)
plaintext = cipher.decrypt(enc)
if laber:
print("rcvd_packet:", plaintext.hex())
print("rcvhdr:", hdr.hex())
try:
cipher.verify(tag)
return plaintext
except:
return None
def send_data(dst, data):
global dsn
dsn += 1
if dsn > 255:
dsn = 0
hdr = bytearray.fromhex("41cc")
hdr.append(dsn)
hdr.extend(PANID)
hdr.extend(reversed(dst))
hdr.extend(EXTENDED_ADDRESS)
if laber:
print("hdr:", hdr.hex())
cntr = int(time.time())
cntrb = struct.pack('<L', cntr)
nonce = bytearray(cntrb)
nonce.extend(EXTENDED_ADDRESS)
nonce.append(0)
if laber:
print("nonce:", nonce.hex())
cipher = AES.new(masterkey, AES.MODE_CCM, nonce, mac_len=4)
cipher.update(hdr)
ciphertext, tag = cipher.encrypt_and_digest(data)
out = ciphertext+tag+cntrb
timaccop.mac_data_req(dst, PANID, 12, dsn, out)
def process_assoc(pkt, data):
ti = TagInfo._make(struct.unpack('<BQHHBHHHHHHB11s',data))
print(ti)
ai = AssocInfo(
checkinDelay=CHECKIN_DELAY,
retryDelay=RETRY_DELAY,
failedCheckinsTillBlank=FAILED_CHECKINS_TILL_BLANK,
failedCheckinsTillDissoc=FAILED_CHECKINS_TILL_DISSOC,
newKey=masterkey,
rfu=bytearray(8*[0])
)
print(ai)
ai_pkt = bytearray([ PKT_ASSOC_RESP ]) + bytearray(struct.pack('<LLHH16s8s', *ai))
send_data(pkt['src_add'], ai_pkt)
def prepare_image(client):
is_bmp = False
base_name = os.path.join(IMAGE_DIR, bytes(client).hex())
filename = base_name + ".png"
print("Reading image file:" + base_name + ".bmp/.png")
if os.path.isfile(filename):
print("Using "+filename+" file")
elif os.path.isfile(base_name + ".bmp"):
is_bmp = True
filename = base_name + ".bmp"
print("Using .bmp file")
elif discover == True:
generate_discover_image(filename)
print("NEW DEVICE")
print(filename)
else:
print("Device not found")
return(0,0)
modification_time = os.path.getmtime(filename)
creation_time = os.path.getctime(filename)
imgVer = int(modification_time)<<32|int(creation_time) # This uses the mofidication time of the image to look for the newest one
file_conv = os.path.join(IMAGE_WORKDIR, bytes(client).hex().upper() + "_" + str(imgVer) + ".bmp") # also use the MAC in case 1 images are created within 1 second
if not os.path.isfile(file_conv):
if is_bmp:
bmp2grays.convertImage(1, "1bppR", filename, file_conv)
else:
Image.open(filename).convert("RGB").save(os.path.join(IMAGE_WORKDIR, "tempConvert.bmp"))
bmp2grays.convertImage(1, "1bppR", os.path.join(IMAGE_WORKDIR, "tempConvert.bmp"), file_conv)
imgLen = os.path.getsize(file_conv)
return (imgVer, imgLen)
def get_firmware_offset(hwType):
if hwType == HW_TYPE_42_INCH_SAMSUNG:
return HW_TYPE_42_INCH_SAMSUNG_ROM_VER_OFST
if hwType == HW_TYPE_74_INCH_DISPDATA:
return HW_TYPE_74_INCH_DISPDATA_ROM_VER_OFST
if hwType == HW_TYPE_74_INCH_DISPDATA_FRAME_MODE:
return HW_TYPE_74_INCH_DISPDATA_ROM_VER_OFST
if hwType == HW_TYPE_29_INCH_DISPDATA:
return HW_TYPE_29_INCH_DISPDATA_ROM_VER_OFST
if hwType == HW_TYPE_29_INCH_DISPDATA_FRAME_MODE:
return HW_TYPE_29_INCH_DISPDATA_ROM_VER_OFST
if hwType == HW_TYPE_ZBD_EPOP50:
return HW_TYPE_ZBD_EPOP50_ROM_VER_OFST
if hwType == HW_TYPE_ZBD_EPOP900:
return HW_TYPE_ZBD_EPOP900_ROM_VER_OFST
if hwType == HW_TYPE_29_INCH_ZBS_026 or hwType == HW_TYPE_29_INCH_ZBS_026_FRAME_MODE or hwType == HW_TYPE_29_INCH_ZBS_025 or hwType == HW_TYPE_29_INCH_ZBS_025_FRAME_MOD
E or hwType == HW_TYPE_154_INCH_ZBS_033 or hwType == HW_TYPE_154_INCH_ZBS_033_FRAME_MODE or hwType == HW_TYPE_42_INCH_ZBS_026 or hwType == HW_TYPE_42_INCH_ZBS_026_FRAME_MOD
E:
return HW_TYPE_29_INCH_ZBS_ROM_VER_OFST
def prepare_firmware(hwType):
filename = 'UPDT{0:0{1}X}.BIN'.format(hwType,4)
if laber:
print("Reading firmware file:", filename)
if not os.path.isfile(filename):
if laber:
print("No Firmware file available")
return (0,0)
f = open(filename,mode='rb')
f.seek(get_firmware_offset(hwType))
firmwareVersionData = f.read(8)
f.close()
osVer = int.from_bytes(firmwareVersionData, "little") & VERSION_SIGNIFICANT_MASK | hwType << 48
osLen = os.path.getsize(filename)
return (osVer, osLen)
def get_image_data(imgVer, offset, length):
filename = os.path.join(IMAGE_WORKDIR, imgVer + ".bmp")
if laber:
print("Reading image file:", filename)
f = open(filename,mode='rb')
f.seek(offset)
image_data = f.read(length)
f.close()
return image_data
def get_fw_data(hwType, offset, length):
filename = 'UPDT{0:0{1}X}.BIN'.format(hwType,4)
if laber:
print("Reading firmware file:", filename)
f = open(filename,mode='rb')
f.seek(offset)
fw_data = f.read(length)
f.close()
return fw_data
def process_checkin(pkt, data):
ci = CheckinInfo._make(struct.unpack('<QHHBBB6s',data))
print(ci)
imgVer = 0
imgLen = 0
try:
imgVer, imgLen = prepare_image(pkt['src_add'])
except Exception as e :
print("Unable to prepare image data for client", pkt['src_add'])
print(e)
osVer = 0
osLen = 0
try:
osVer, osLen = prepare_firmware(ci.hwType)
except Exception as e :
print("Unable to prepare firmware data for client", pkt['src_add'])
print(e)
pi = PendingInfo(
imgUpdateVer = imgVer,
imgUpdateSize = imgLen,
osUpdateVer = osVer,
osUpdateSize = osLen,
nextCheckinDelay = 0,
rfu=bytearray(4*[0])
)
print(pi)
pi_pkt = bytearray([ PKT_CHECKOUT ]) + bytearray(struct.pack('<QLQLL4s', *pi))
send_data(pkt['src_add'], pi_pkt)
def process_download(pkt, data):
cri = ChunkReqInfo._make(struct.unpack('<QLBB6s',data))
if laber:
print(cri)
ci = ChunkInfo(
offset = cri.offset,
osUpdatePlz = cri.osUpdatePlz,
rfu = 0,
)
if laber:
print(ci)
try:
if ci.osUpdatePlz:
fdata = get_fw_data(cri.versionRequested>>48, cri.offset, cri.len)
else:
fdata = get_image_data(bytes(pkt['src_add']).hex().upper() + "_" + str(cri.versionRequested), cri.offset, cri.len)
except Exception as e :
print("Unable to get data for version", cri.versionRequested)
print(e)
return
outpkt = bytearray([ PKT_CHUNK_RESP ]) + bytearray(struct.pack('<LBB', *ci)) + bytearray(fdata)
if laber:
print("sending chunk", len(outpkt), outpkt[:10].hex() ,"...")
send_data(pkt['src_add'], outpkt)
def generate_discover_image(filename):
muster=Image.new("RGB",(296,128),color=(255,255,255))
named_tuple = time.localtime() # get struct_time
time_string = time.strftime("%m/%d/%Y, %H:%M:%S", named_tuple)
im = ImageDraw.Draw(muster)
font = ImageFont.load_default()
length_name=font.getbbox("Aktivierung")
im.text((((Display_Size_x/2)-length_name[2]/2),5),"Aktivierung" ,fill=(0, 0, 0),font=font)
length_name=font.getbbox(filename)
im.text((((Display_Size_x/2)-length_name[2]/2),45),filename ,fill=(0, 0, 0),font=font)
box=font.getbbox(time_string)
tboy1=90
tboy2=box[3]+tboy1
tbox1=((Display_Size_x-box[2])/2)
tbox2=((Display_Size_x-box[2])/2)+box[2]
im.rectangle((tbox1-6,tboy1-2,tbox2+6,tboy2+2),fill=(255,0,0),outline=(0,0,0),width=2)
im.text((tbox1,tboy1),time_string,fill=(255,255,255),font=font)
muster=muster.rotate(angle=90,expand="true")
muster.save(filename)
def generate_pkt_header(pkt): #hacky- timaccop cannot provide header data
bcast = True
if pkt['dst_add'] == b'\xff\xff': #broadcast assoc
hdr = bytearray.fromhex("01c8")
else:
hdr = bytearray.fromhex("41cc")
bcast = False
hdr.append(pkt['dsn'])
hdr.extend(pkt['dst_pan_id'])
hdr.extend(pkt['dst_add'])
if bcast:
hdr.extend(pkt['src_pan_id'])
hdr.extend(reversed(pkt['src_add']))
return hdr
def process_pkt(pkt):
hdr = generate_pkt_header(pkt)
if len(pkt['data']) < 10:
print("Received a too short paket")
print("data", pkt['data'].hex())
return
nonce = bytearray(pkt['data'][-4:])
nonce.extend(reversed(pkt['src_add']))
nonce.extend(b'\x00')
tag = pkt['data'][-8:-4]
ciphertext = pkt['data'][:-8]
plaintext = decrypt(hdr, ciphertext, tag, nonce)
if not plaintext:
print("data", pkt['data'].hex())
print("hdr", hdr.hex())
print("ciph", ciphertext.hex())
print("nonce", nonce.hex())
print("tag", tag.hex())
print("packet is NOT authentic")
return
typ = plaintext[0]
if typ == PKT_ASSOC_REQ:
print("Got assoc request")
process_assoc(pkt, plaintext[1:])
elif typ == PKT_CHECKIN:
print("Got checkin request")
process_checkin(pkt, plaintext[1:])
elif typ == PKT_CHUNK_REQ:
if laber:
print("Got chunk request")
process_download(pkt, plaintext[1:])
else:
print("Unknown request", typ)
timaccop.init(PORT, PANID, CHANNEL, EXTENDED_ADDRESS, process_pkt)
print("Station started")
timaccop.run()
Code: Alles auswählen
import timaccop
from Cryptodome.Cipher import AES
from collections import namedtuple
import struct
import os
import logging
from PIL import Image
import binascii
import time
from io import BytesIO
masterkey = bytearray.fromhex("D306D9348E29E5E358BF2934812002C1")
PORT = "COM5"
EXTENDED_ADDRESS = [ 0x00, 0x12, 0x4B, 0x00, 0x14, 0xD9, 0x49, 0x35 ]
PANID = [ 0x47, 0x44 ]
CHANNEL = 11
IMAGE_WORKDIR = "tmp/"
PKT_ASSOC_REQ = (0xF0)
PKT_ASSOC_RESP = (0xF1)
PKT_CHECKIN = (0xF2)
PKT_CHECKOUT = (0xF3)
PKT_CHUNK_REQ = (0xF4)
PKT_CHUNK_RESP = (0xF5)
TagInfo = namedtuple('TagInfo', """
protoVer,
swVer,
hwType,
batteryMv,
rfu1,
screenPixWidth,
screenPixHeight,
screenMmWidth,
screenMmHeight,
compressionsSupported,
maxWaitMsec,
screenType,
rfu
""")
AssocInfo = namedtuple('AssocInfo', """
checkinDelay,
retryDelay,
failedCheckinsTillBlank,
failedCheckinsTillDissoc,
newKey,
rfu
""")
CheckinInfo = namedtuple('CheckinInfo', """
swVer,
hwType,
batteryMv,
lastPacketLQI,
lastPacketRSSI,
temperature,
rfu,
""")
PendingInfo = namedtuple('PendingInfo', """
imgUpdateVer,
imgUpdateSize,
osUpdateVer,
osUpdateSize,
nextCheckinDelay,
rfu
""")
ChunkReqInfo = namedtuple('ChunkReqInfo', """
versionRequested,
offset,
len,
osUpdatePlz,
rfu,
""")
ChunkInfo = namedtuple('ChunkInfo', """
offset,
osUpdatePlz,
rfu,
""")
logging.basicConfig(format='%(asctime)s %(message)s')
logger = logging.getLogger(__name__)
dsn = 0
def print(*args):
msg = ""
for arg in args:
msg += str(arg) + " "
logger.warning(msg)
def decrypt(hdr, enc, tag, nonce):
cipher = AES.new(masterkey, AES.MODE_CCM, nonce, mac_len=4)
cipher.update(hdr)
plaintext = cipher.decrypt(enc)
#print("rcvd_packet:", plaintext.hex())
#print("rcvhdr:", hdr.hex())
try:
cipher.verify(tag)
return plaintext
except:
return None
def send_data(dst, data):
global dsn
dsn += 1
if dsn > 255:
dsn = 0
hdr = bytearray.fromhex("41cc")
hdr.append(dsn)
hdr.extend(PANID)
hdr.extend(reversed(dst))
hdr.extend(EXTENDED_ADDRESS)
#print("hdr:", hdr.hex())
cntr = int(time.time())
cntrb = struct.pack('<L', cntr)
nonce = bytearray(cntrb)
nonce.extend(EXTENDED_ADDRESS)
nonce.append(0)
#print("nonce:", nonce.hex())
cipher = AES.new(masterkey, AES.MODE_CCM, nonce, mac_len=4)
cipher.update(hdr)
ciphertext, tag = cipher.encrypt_and_digest(data)
out = ciphertext+tag+cntrb
timaccop.mac_data_req(dst, PANID, 12, dsn, out)
def process_assoc(pkt, data):
ti = TagInfo._make(struct.unpack('<BQHHBHHHHHHB11s',data))
print(ti)
ai = AssocInfo(
checkinDelay=300000, #check each 900sec
retryDelay=1000, #retry delay 1000ms
failedCheckinsTillBlank=2,
failedCheckinsTillDissoc=0,
newKey=masterkey,
rfu=bytearray(8*[0])
)
print(ai)
ai_pkt = bytearray([ PKT_ASSOC_RESP ]) + bytearray(struct.pack('<LLHH16s8s', *ai))
send_data(pkt['src_add'], ai_pkt)
def prepare_image(client):
filename = bytes(client).hex() + ".png"
print("Reading image file:", filename)
modification_time = os.path.getmtime(filename)
creation_time = os.path.getctime(filename)
pf = open(filename,mode='rb')
imgData = pf.read()
imgVer = int(modification_time)<<32|int(creation_time) # This uses the mofidication time of the image to look for the newest one
#imgVer = binascii.crc32(imgData) # This uses the CRC of the image to look for a newer one but can fail as on "stock" custom firmware the highest number is used
pf.close()
file_conv = IMAGE_WORKDIR + str(imgVer) + ".bmp"
if not os.path.isfile(file_conv):
pngdata = BytesIO(imgData)
im = Image.open(pngdata)
im_L = im.convert("1")
im_L.save(file_conv)
imgLen = os.path.getsize(file_conv)
return (imgVer, imgLen)
def get_image_data(imgVer, offset, length):
filename = IMAGE_WORKDIR + str(imgVer) + ".bmp"
print("Reading image file:", filename)
f = open(filename,mode='rb')
f.seek(offset)
image_data = f.read(length)
f.close()
return image_data
def process_checkin(pkt, data):
ci = CheckinInfo._make(struct.unpack('<QHHBBB6s',data))
print(ci)
try:
imgVer, imgLen = prepare_image(pkt['src_add'])
except Exception as e :
print("Unable to prepare image data for client", pkt['src_add'])
print(e)
return
pi = PendingInfo(
imgUpdateVer = imgVer,
imgUpdateSize = imgLen,
osUpdateVer = ci.swVer,
osUpdateSize = 0,
nextCheckinDelay = 0,
rfu=bytearray(4*[0])
)
print(pi)
pi_pkt = bytearray([ PKT_CHECKOUT ]) + bytearray(struct.pack('<QLQLL4s', *pi))
send_data(pkt['src_add'], pi_pkt)
def process_download(pkt, data):
cri = ChunkReqInfo._make(struct.unpack('<QLBB6s',data))
print(cri)
ci = ChunkInfo(
offset = cri.offset,
osUpdatePlz = 0,
rfu = 0,
)
print(ci)
try:
fdata = get_image_data(cri.versionRequested, cri.offset, cri.len)
except Exception as e :
print("Unable to get image data for version", cri.versionRequested)
print(e)
return
outpkt = bytearray([ PKT_CHUNK_RESP ]) + bytearray(struct.pack('<LBB', *ci)) + bytearray(fdata)
print("sending chunk", len(outpkt), outpkt[:10].hex() ,"...")
send_data(pkt['src_add'], outpkt)
def generate_pkt_header(pkt): #hacky- timaccop cannot provide header data
bcast = True
if pkt['dst_add'] == b'\xff\xff': #broadcast assoc
hdr = bytearray.fromhex("01c8")
else:
hdr = bytearray.fromhex("41cc")
bcast = False
hdr.append(pkt['dsn'])
hdr.extend(pkt['dst_pan_id'])
hdr.extend(pkt['dst_add'])
if bcast:
hdr.extend(pkt['src_pan_id'])
hdr.extend(reversed(pkt['src_add']))
return hdr
def process_pkt(pkt):
hdr = generate_pkt_header(pkt)
if len(pkt['data']) < 10:
print("Received a too short paket")
print("data", pkt['data'].hex())
return
nonce = bytearray(pkt['data'][-4:])
nonce.extend(reversed(pkt['src_add']))
nonce.extend(b'\x00')
tag = pkt['data'][-8:-4]
ciphertext = pkt['data'][:-8]
plaintext = decrypt(hdr, ciphertext, tag, nonce)
if not plaintext:
print("data", pkt['data'].hex())
print("hdr", hdr.hex())
print("ciph", ciphertext.hex())
print("nonce", nonce.hex())
print("tag", tag.hex())
print("packet is NOT authentic")
return
typ = plaintext[0]
if typ == PKT_ASSOC_REQ:
print("Got assoc request")
process_assoc(pkt, plaintext[1:])
elif typ == PKT_CHECKIN:
print("Got checkin request")
process_checkin(pkt, plaintext[1:])
elif typ == PKT_CHUNK_REQ:
print("Got chunk request")
process_download(pkt, plaintext[1:])
else:
print("Unknown request", typ)
timaccop.init(PORT, PANID, CHANNEL, EXTENDED_ADDRESS, process_pkt)
print("Station started")
timaccop.run()
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
Benutze am besten die aktuellste aus dem Repo, ROT habe ich letztens erst mit eingebaut.
Sieht so aus als nutzt du noch die ältere version
Sieht so aus als nutzt du noch die ältere version
Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung
hm, ich hab mal die aktuelle stations.py ausprobiert.
Ich sehe die Grafik auf dem Display jetzt diagonal verzerrt. Das rot scheint jetzt aber mit angezeigt zu werden.
Öfters erhalte ich aber auf dem Display nur noch den Blank-Screen.
Ich sehe die Grafik auf dem Display jetzt diagonal verzerrt. Das rot scheint jetzt aber mit angezeigt zu werden.
Öfters erhalte ich aber auf dem Display nur noch den Blank-Screen.