Elektronisches Preisschild Sammelbestellung - Ansteuerung

Der chaotische Hauptfaden

Moderatoren: Heaterman, Finger, Sven, TDI, Marsupilami72, duese

Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

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.
Benutzeravatar
phettsack
Beiträge: 1186
Registriert: Mo 12. Aug 2013, 18:17

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von phettsack »

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.
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

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

Code: Alles auswählen

network_key: [ 0xD3,0x06,0xD9,0x34,0x8E, 0x29, 0xE5, 0xE3, 0x58, 0xBF, 0x29, 0x34, 0x81, 0x20, 0x02, 0xC1 ]
führt auch nicht zu Funktion.
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Das Preisschild läuft definitiv nur mit dem Stick auf dem die TiMac Firmware drauf ist.
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

Also kein ZigBee, sondern nur sowas ähnliches auf 802.15.4 basierend? Schade...
Benutzeravatar
michabe
Beiträge: 61
Registriert: Sa 28. Mai 2022, 15:29
Wohnort: JO52dc

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von michabe »

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 ?
Ich hab da mal was messen lassen:
Bild
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

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:

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 
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.
Benutzeravatar
ProgBernie
Beiträge: 584
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

Ich habe station.py wie folgt abgeändert:

Code: Alles auswählen

def process_pkt(pkt):
    if laber:
        print("pkt", pkt)
        print("pkt['data']", pkt['data'].hex())
Damit erhalte ich bei einem reset des Schildes:

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
...
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

Danke, das muss ich in Ruhe verdauen. Da sind Ähnlichkeiten und Unterschiede...
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

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.
Benutzeravatar
ProgBernie
Beiträge: 584
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

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.
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

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.

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
Vielleicht sollte ich einfach auf den bestellten passenden CC Stick warten, dann lässt sich das einfacher umbauen.
Benutzeravatar
sukram
Beiträge: 3063
Registriert: Sa 10. Mär 2018, 18:27
Wohnort: Leibzsch

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von sukram »

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
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

Ja doch schon. Wenn ich das richtig verstanden haben sollte das so ablaufen:

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
- ...
Wie gesagt, ich warte einfach bis der Stick da ist, dann sollte sich das ganz einfach lösen lassen.
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Außen Temperaturanzeige aus der Influxdb gesaugt.

897095CB-1351-4407-981B-CD98EEFF98C1.jpeg
Benutzeravatar
ProgBernie
Beiträge: 584
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

omega hat geschrieben: Sa 5. Nov 2022, 20:52 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,
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.
Benutzeravatar
ProgBernie
Beiträge: 584
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

Hightech hat geschrieben: Sa 5. Nov 2022, 22:55 Außen Temperaturanzeige aus der Influxdb gesaugt.


897095CB-1351-4407-981B-CD98EEFF98C1.jpeg
Nett. Ich häkel gerade eine Wetteranzeige aus OWM zusammen. Bin schon am Bilder malen.
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

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
C9845D34-3670-4607-90B5-1F3BF17ABDED.jpeg
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

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.
Benutzeravatar
omega
Beiträge: 520
Registriert: So 11. Aug 2013, 14:36
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von omega »

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:
restmuell.jpg
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()
Benutzeravatar
T5000
Beiträge: 140
Registriert: Mo 19. Aug 2013, 11:57
Wohnort: Lichtenau

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von T5000 »

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
duese
Beiträge: 6059
Registriert: So 11. Aug 2013, 17:56

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von duese »

Rot halt. In RGB: 255,0,0 bzw 100%,0%,0%
Benutzeravatar
T5000
Beiträge: 140
Registriert: Mo 19. Aug 2013, 11:57
Wohnort: Lichtenau

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von T5000 »

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)
station_py_hightech.PNG

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()

Meine aktuelle station.py ohne rot:

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()

kann mir jemand weiterhelfen?
Lokaro
Beiträge: 16
Registriert: So 20. Nov 2022, 23:18

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Lokaro »

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
Benutzeravatar
T5000
Beiträge: 140
Registriert: Mo 19. Aug 2013, 11:57
Wohnort: Lichtenau

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von T5000 »

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.
Benutzeravatar
Bastelbruder
Beiträge: 11482
Registriert: Mi 14. Aug 2013, 18:28

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Bastelbruder »

Diagonal verzerrt
Sieht das so aus wie auf der Deppenlampe ohne Zeilensynchronisation?
Dann tippe ich auf falsche Anzahl Pixel in X-Richtung. Das kann durchaus zu leeren Bildern führen, es ist aber nicht auszuschließen daß die Y-Größe dann auch nicht stimmt.
Benutzeravatar
T5000
Beiträge: 140
Registriert: Mo 19. Aug 2013, 11:57
Wohnort: Lichtenau

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von T5000 »

Ich hab mal eines meiner Testbilder angehängt.
Die Pixelmaße sind 296x146
000002838f9c3b12.png
000002838f9c3b12.png (2.23 KiB) 1726 mal betrachtet
Mit dem alten Script gehts, mit dem neuen nicht.
Auch eine abschneiden von jeweils 10 Pixel in Länge und Breite bringt leider keine Besserung.

Nachtrag:

wenn ich in den /tmp Ordner schaue, stelle ich fest, das die Bilder nicht korrekt konvertiert werden. TempConvert.bmp lässt sich meist noch mit einem Bildbetrachter anzeigen. Die anderen erzeugten Bilder die "000002838CCA3B12_7176246181206894028.bmp" oder ähnlich heißen lassen sich nicht öffnen. Die mit der alten Station.py erzeugten Bilder "7176216331184172200.bmp" hingegen schon.
berferd
Beiträge: 1327
Registriert: Mi 3. Apr 2019, 23:45

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von berferd »

Mal eine grundlegende Frage... ich überlege grade wie ich das Ding möglichst einfach & energiesparend dauerhaft betreibe.
Ich habe hier keinen extra Router, Pi o.ä. der "ohnehin immer läuft" und den ich als Server nutzen könnte. Alle meine Geräte (Desktop, Laptop) schalte ich bei Nichtgebrauch aus oder in den Ruhemodus.
Ich würde gerne vermeiden, extra einen Pi o.ä. hinzustellen, der dann 24/7 die nächsten Jahre nur dafür durchläuft und rund um die Uhr 3-5 Watt schlürft.
Also, was nimmt man als minimalistische Plattform? "alles selber entwerfen und bauen" scheidet aus.
Idealerweise sollte das Ding Zigbee (natürlich) können, und Ethernet und/oder Wifi (vermutlich ersteres stromsparender), und man sollte selber einfache eigene Programme drauf starten können (Programmiersprache egal. Meinetwegen auch nur Shell und compiliertes C.).
Lokaro
Beiträge: 16
Registriert: So 20. Nov 2022, 23:18

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Lokaro »

Die bilder werden in 296x128 erwartet und müssen auch so vorliegen
T5000 hat geschrieben: Mo 12. Dez 2022, 13:58 Die Pixelmaße sind 296x146
Und zum nachtrag, durch das ROT in den Bildern werden sie in ein altes BMP format konvertiert was so gut wie keine software mehr unterstützt, die firmware im display aber schon.
Lokaro
Beiträge: 16
Registriert: So 20. Nov 2022, 23:18

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Lokaro »

@berferd

Du könntest eine Station auch nur für ca. 20 Minuten starten um die Displays upzudaten und den rest des Tages aus. Die Displays suchen alle 15 Minuten nach der Station.

Es gibt auch eine ESP32 Station, dadurch läuft alles auf diesem.

Als Zigbee transceiver wird eine Display Platine genommen und mit einer eigenen firmware als Access Point genutzt, diese flasht der ESP32 selber

Die software funktioniert ist aber noch im beta status.

Das Repo ist hier:
https://github.com/jjwbruijn/ESP32-epaper-station
Benutzeravatar
Später Gast
Beiträge: 1680
Registriert: Di 5. Apr 2016, 22:03
Wohnort: Karlsruhe
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Später Gast »

An dem Energieverbrauch denk ich auch grad rum. Muss grad primär eine Wohnung neu beleuchten und da wird wohl zigbee zum Einsatz kommen. Esp32 kann das auch, wenn man sich also als gateway nen esp hernimmt, passt das da vllt grad auch noch drauf.

Wenn man die Informationsbeschaffung der Displays irgendwie extern takten könnte, kann der Esp in der Zwischenzeit auch aus sein. Alle gleichzeitig anschalten führt nach längerer Betriebszeit bestimmt zu Phasenverschiebungen und damit Ausfällen.

Fritzboxen können ja nebenher teils auch schon smart Kram, leider nur sehr eingeschränkt und selber sachen dazupatchen ist eher nicht, oder gibts Freetz noch? Router mit OpenWRT?
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Mein Plan ist, ein 2x3 Displaymatrix auf dem ich meine Daten darstelle.
Die Display kann man parallel an einen Akku klemmen und über eine ttl- Daisychain hintereinander schalten und mit einem nem ESP32 mit Daten füttern.
Die Funkdaten laufen dann nur über den ESP.
Wlan halt dann.
Benutzeravatar
T5000
Beiträge: 140
Registriert: Mo 19. Aug 2013, 11:57
Wohnort: Lichtenau

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von T5000 »

Danke für den Tipp mit der richtigen Auflösung, ich weis auch nicht mehr wo ich meine falschen Werte her hatte.
epaper.PNG
Display1 : altes station.py Script - Bild in Graustufen ohne rot im PNG
Display2 : neues station.py Script - gleiches Bild wie Display1 -> die Graustufen fehlen, Mario hat keine Hände usw :shock:
Display3 : neues station.py Script - Bild mit rot im PNG

Die Graustufen fehlen halt im neuen Script. Wird sicherlich an dem ungewöhnlichen BMP Format liegen.
Ideal wäre natürlich, wenn das Script erkennt, das es ein Graustufen PNG ist und es dann in das modernere BMP wandelt. ;)

Ich bin erstmal froh, das ich überhaupt soweit gekommen bin, inkl. C2531 Flashen usw. :D
Teslafreak
Beiträge: 4
Registriert: Do 15. Aug 2013, 21:49

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Teslafreak »

Diese Ständer kann man für die Displays wunderbar zweckentfremden: https://www.thingiverse.com/thing:5422488
2.jpg
1.jpg
nero
Beiträge: 698
Registriert: Mo 12. Aug 2013, 11:58
Wohnort: Oberbayern

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von nero »

kwh.png
kwh.png (4.88 KiB) 1479 mal betrachtet
Mhhhhahprprhrhprrr
xanakind
Beiträge: 12538
Registriert: So 11. Aug 2013, 21:55

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von xanakind »

Was genau möchtest du uns denn mit diesem Post sagen?
Bitte schreibe doch einen vollständigen Satz in einer Sprache, welche wir lesen können.
Benutzeravatar
ferdimh
Beiträge: 9381
Registriert: Fr 16. Aug 2013, 15:19

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ferdimh »

Es wird eindeutig die Änderungsrate der eingespeisten Leistung in Kilowatt pro Stunde angezeigt...
Benutzeravatar
Fritzler
Beiträge: 12579
Registriert: So 11. Aug 2013, 19:42
Wohnort: D:/Berlin/Adlershof/Technologiepark
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Fritzler »

Kontext Mädels!
Es geht um die ausgefransten Buchstaben durch Subpixelrendering umgemappt auf 1bit Graustufen Epaper und die immernoch fehlende Lösung dazu.
MSG
Beiträge: 2182
Registriert: Fr 9. Nov 2018, 23:24
Wohnort: Nähe Dieburg

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von MSG »

Aber gab es nicht früher (tm) Schriften extra für den Bildschirm? Da war doch das gleiche Problem, bis die grafischen OS die Druckerschriften entsprechend rendern konnten.

Evtl wäre das ein Ansatzpunkt?

Die Adafruit Grafikbibliotheken haben soweit mir dünkt auch spezielle Schriften für die kleinen Grafik Panels.
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Ich hab was in Python gebastelt mit Skalierung und min/Max.
Klappt leider noch nicht 100 bei negativen Zahlen kackts ab
225F09B3-6865-4023-A074-66BC901CB7C2.jpeg
Flip
Beiträge: 637
Registriert: Mi 14. Aug 2013, 12:04

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Flip »

Ich bin ja in meinem Gesamten System auf der Variante ESP32-gateway-Station. Die Sendezeit ist ja durchaus begrenzt, wenn man den Äther nicht verstopft haben will.
Mich stört es etwas, immer die pixelgrafik zu übertragen, auch wenn komprimiert, hat man da doch erheblich mehr daten, als wenn man Schrift und grafik auf dem Display rechnet. Selbst mit 1MHz kerntakt dürfte das fixer gehen als das rüberschieben der grafik.


Ich denke erstmal effizienzverliebt an Protobuf-codierte Zeichenbefehle. 1 byte Typ und Farbe, 2 Byte Position und Größe, dann ggf für Text oder Kurven noch ein Datenstring Fällt da jemandem noch etwas ein, was besser für differentielle screen-updates geht?
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

So, nun :D
Hier 6 Display uarts in Reihe an einem ESP32

Der holt sich die Daten direkt aus der InfluxDB und geht dann schlafen, nachdem er den Strom für die Displays aus gemacht hat.
2D741113-6334-43E6-B8CF-41871BF7204D.jpeg
berferd
Beiträge: 1327
Registriert: Mi 3. Apr 2019, 23:45

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von berferd »

Hat jemand zufällig einige Adapterplatinen (so wie hier beschrieben https://www.pcbway.com/project/sharepro ... a845c.html) über?
Dann muss ich nicht extra nur für meine 5 Stück welche fertigen lassen....
Benutzeravatar
ProgBernie
Beiträge: 584
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

Flip hat geschrieben: Fr 30. Dez 2022, 21:45 Ich bin ja in meinem Gesamten System auf der Variante ESP32-gateway-Station. Die Sendezeit ist ja durchaus begrenzt, wenn man den Äther nicht verstopft haben will.
Mich stört es etwas, immer die pixelgrafik zu übertragen, auch wenn komprimiert, hat man da doch erheblich mehr daten, als wenn man Schrift und grafik auf dem Display rechnet. Selbst mit 1MHz kerntakt dürfte das fixer gehen als das rüberschieben der grafik.


Ich denke erstmal effizienzverliebt an Protobuf-codierte Zeichenbefehle. 1 byte Typ und Farbe, 2 Byte Position und Größe, dann ggf für Text oder Kurven noch ein Datenstring Fällt da jemandem noch etwas ein, was besser für differentielle screen-updates geht?
Es wäre ja schon viel gewonnen, wenn nicht dieses dusselige unkomprimierte BMP-Format benutzt würde. Das sind auch für ein komplett einfarbiges Schild aktuell 9542 Byte. Als GIF sind das meist deutlich weniger Byte, bei meinen Wetterbildern etwa 2200, als PNG noch darunter 1800 Byte. Ein einfarbiges Bild sind als PNG nur noch 159 Byte.
Lokaro
Beiträge: 16
Registriert: So 20. Nov 2022, 23:18

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Lokaro »

Eine komprimierung ist in arbeit :)

Bei den großen ist nun Gzip implementiert und funktioniert sehr gut. Leider haben die ZBS243 aber zu wenig RAM um das dort zu implementieren.
https://youtu.be/kPy8rIQ75NU
Benutzeravatar
Bastelbruder
Beiträge: 11482
Registriert: Mi 14. Aug 2013, 18:28

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Bastelbruder »

Ich bin jetzt nicht der Spezialist in Bilddatenformaten, aber ich war bei der Prüfung der Kinderschuhe der elektronischen Bildverarbeitung mit dabei. Viele der heute völlig unnötig mitgeschleppten Begleitdaten fressen bei so kleinen Bildern den Gewinn auf.

Da sollte man wirklch mal die Statis-Tiger dranlassen, sehr wahrscheinlich bringt eine primitivste Lauflängencodierung die höchste Ersparnis, natürlich abhängig vom Bildinhalt - ein unregelmäßiges Raster ist die Höchststrafe.
Ich hab eben geschwind mit IrfanView eine aus dem Leben gegriffene SW-Grafik (296 x 128 Pixel, bmp: 5182 Bytes) durchprobiert, da hat (tif) CCITT Fax 4 mit 1416 Bytes gegenüber allen anderen Algorithmen die Nase weit vorn. png belegt mit 2120 Bytes den zweiten Platz und huffmann kommt noch vor gif.
Schalter aus dem Watkins-Johnson
Schalter aus dem Watkins-Johnson
bitmaps.png (6.05 KiB) 935 mal betrachtet
Alle weiter oben gesehenen Musterdisplays lassen sich natürlich viel effektiver komprimieren, für Wetterbilder dürfte Fax 4 der Spitzenreiter sein.

Ein einzelner Pixel in der Bildmitte wird in (tif) CCITT Fax 4 mit ganzen 254 Bytes dargestellt, Fax3: 666, huffmann 510, gif 295, png kommt auf Platz 1 mit 144 Bytes.

Bei der Gelegenheit (habt Ihr im IrfanView schonmal die Taste [F3] benutzt?) fällt auf daß die populären Formate natürlich auch Format, teilweise Größe (dpi) und nicht zuletzt den Namen des Kompressionsbeauftragten beinhalten, das brauchen wir hier alles nicht.
Lokaro
Beiträge: 16
Registriert: So 20. Nov 2022, 23:18

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Lokaro »

Wenn RLE auch am einfachsten zu implementieren wäre macht es leider zu schnell keinen sinn mehr da die Daten zu groß werden.

CCITT T.4 ist derzeit der Favorit noch etwas vor .png um es als System umgreifende Komprimierung zu nutzen.
Kerko
Beiträge: 336
Registriert: Mo 12. Aug 2013, 22:18

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Kerko »

Hat noch Jemand das Problem, dass einzelne Displays Ihre Batterien innerhalb von 14 Tagen leersaugen? Hängen alle an der gleichen Basis mit dem gleichen Updateintervall. Manche ziehen neue Batterien innerhalb von 14 Tagen leer, manche nicht.
Benutzeravatar
Hightech
Beiträge: 11306
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Ich glaube da gibt es einen Bug, das Display hängt sich auf und macht die Batterie platt.

Hab ich auch schon beobachtet.
Benutzeravatar
ProgBernie
Beiträge: 584
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

Hightech hat geschrieben: Fr 13. Jan 2023, 18:44 Ich glaube da gibt es einen Bug, das Display hängt sich auf und macht die Batterie platt.

Hab ich auch schon beobachtet.
Ein Bug in der Firmware der Schilder würde das erklären. Dann wird vermutlich der RF-Kram nicht abgeschaltet. Der RF-Kram braucht Unmengen an Strom (>30mA), der Rest nicht.

Ich habe auch beobachtet daß ein Schild oft stundenlang keine neue Anzeige schaltet, obwohl diese bereit steht. Im Log habe ich gefunden, daß diese Schilder oft bei jedem Update die Datei bekommen, inzwischen läuft das im Debug hier und ich warte aufs Auftreten. Dann kann ich sehen ob der letzte Teil des Bildes auch ausgeliefert wird.
Antworten