Elektronisches Preisschild Sammelbestellung - Ansteuerung

Der chaotische Hauptfaden

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

duese
Beiträge: 5634
Registriert: So 11. Aug 2013, 17:56

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von duese »

Hightech hat geschrieben: Mo 24. Okt 2022, 06:44 Die Schrifart ist Geschmacksache
Diese einfache Form zb geht recht gut:
https://www.1001fonts.com/advanced-pixel-7-font.html
Gerade Linien in 90° gehen am besten.

Oder eine einfache ttf Font
https://www.dafont.com/bitstream-vera-mono.font
Danke!

Noch eine Frage: Wo hast Du das converts.py her? Ich hab eine Konvertierung ins PIL-Format gefunden, mit den konvertierten Datein funktioniert dann aber

Code: Alles auswählen

length_name=font.getbbox(Name)
nicht.
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Ja, muss ich raussuchen.
getbbox funktioniert da nicht, müsste mit getbtext oder so gehen, schau ich mal nach.
duese
Beiträge: 5634
Registriert: So 11. Aug 2013, 17:56

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von duese »

Ok, passt. Die andere Funktion hab ich auch gefunden, klappt also (dann aber nicht mehr mit TTF).

Ich dachte nur, da gibts es noch nen Trick, nachdem in Deinem Schildergenerator PIL mit getbbox kombiniert ist (was aber offenbar nicht geht).
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Eine aktuelle Station.py mit Farbe und Discovery.
Der Discovery-Modus ändert nichts an der Verbingung oder am Paaring. Es wird nur dafür gesorgt, das jedes neue Display eine Grafik bekommt.
Zusätzlich hab ich den Labermodus --l eingeführt. Ohne --l kommen nur die wesentlichen Infos.
Ist übersichtlicher

Code: Alles auswählen

#!/usr/bin/python3
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 = os.environ.get("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()

Hier einmal die convert.py
Die umgewandelten .bfd Dateien müssen aber mit im Verzeichniss liegen.

Code: Alles auswählen

#!/usr/bin/python3
#
# The Python Imaging Library
# $Id$
#
# PIL raster font compiler
#
# history:
# 1997-08-25 fl   created
# 2002-03-10 fl   use "from PIL import"
#

from __future__ import print_function

import glob
import sys

# drivers
from PIL import BdfFontFile
from PIL import PcfFontFile

VERSION = "0.4"

if len(sys.argv) <= 1:
    print("PILFONT", VERSION, "-- PIL font compiler.")
    print()
    print("Usage: pilfont fontfiles...")
    print()
    print("Convert given font files to the PIL raster font format.")
    print("This version of pilfont supports X BDF and PCF fonts.")
    sys.exit(1)

files = []
for f in sys.argv[1:]:
    files = files + glob.glob(f)

for f in files:

    print(f + "...", end=' ')

    try:

        fp = open(f, "rb")

        try:
            p = PcfFontFile.PcfFontFile(fp)
        except SyntaxError:
            fp.seek(0)
            p = BdfFontFile.BdfFontFile(fp)

        p.save(f)

    except (SyntaxError, IOError):
        print("failed")

    else:
        print("OK")
Benutzeravatar
Finger
Administrator
Beiträge: 6558
Registriert: Di 12. Jun 2012, 20:16
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Finger »

Ich esle mich gerade das erste mal mit Python ab.

station.py erzeugt mir diese Ausgabe:
Traceback (most recent call last):
File "C:\Users\Fingeria\Desktop\epaper-station-master\epaper-station-master\station.py", line 3, in <module>
from Cryptodome.Cipher import AES
ModuleNotFoundError: No module named 'Cryptodome'
In der IDE findet sich hingegen das hier:
import Crypto
print(Crypto.__version__)
3.15.0
Soweit so gut. Und nun? Sollte ich erwähnen, das ich zum Testen Windowns nutze? Was mach ich denn da? Ich hab mich an das hier gehalten: https://www.youtube.com/watch?v=qRuMf6yXXyA "How to Install Pycryptodome (Crypto) in Python 3.10"
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Hier steht die ganze Geschichte über die Schilder.
Wie, Was Warum und überhaupt. Alle schmutzigen Details und tricks.
https://dmitry.gr/index.php?r=05.Projec ... ice%20Tags
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Ah, das muss man wissen:
Man muss die aktuellen Versionen von dem Python
Zeug installieren
Auch die Pillow Sachen müssen aktuell sein.

duese hat geschrieben: Mo 24. Okt 2022, 09:46 Ok, passt. Die andere Funktion hab ich auch gefunden, klappt also (dann aber nicht mehr mit TTF).

Ich dachte nur, da gibts es noch nen Trick, nachdem in Deinem Schildergenerator PIL mit getbbox kombiniert ist (was aber offenbar nicht geht).
Benutzeravatar
Zabex
Beiträge: 593
Registriert: Di 2. Jul 2013, 08:45
Wohnort: Aldenhoven
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Zabex »

Hm, ich bekomme den Stick nicht geflashed. Habe als Programmieradapter zuerst einen Arduino-Nano genommen (mit CCloader Firmware). Anschluss über 4 Kabel (GND, DD,DS,RST), Spannungsversorgung durch einstecken des Sticks in USB-Buchse.
Nachdem das einfach nicht klappen wollte, habe ich meinen ASIX PRESTO Programmer mit UP.exe Software rausgekramt und festgestellt, dass der den CC2531F256 kennt. 4 Drähte + Vdd-Sense (Pin2). Spannungsversorgung wie gehabt über USB. Vdd-Sense wird vom Presto als "größer 2V" gemessen. Fuse Bits lassen sich auslesen. Erase geht auch. Wenn ich flashen will, wird gemeckert, dass die ID 1111 1111 1111 1.." ist. Flashen läuft durch, verify ergibt jedoch, dass alle Bytes "FF" sind - also nix geflashed.

Was kann es sein:
- Muss man vielleicht eine der beiden Tasten auf dem Stick drücken?
- Kann der Chip nur 3.3V und der Arduino hat mit seinen 5V auf DD/DS/RST den Chip gehimmelt?
- Braucht der Chip vielleicht 5V an Pin 2?
- vielleicht habe ich zwischen 2 Leitungen versehentlich einen Kurzschluss fabriziert, so dass die bidirektionale Leitung Schaden genomen hat.

Ich nehme an, inzwischen ist der Stick defekt. Habe 2 neue bestellt und frage mich, was ich dann wohl besser zum flashen nehme. Empfehlungen?


Gruß,
Zabex
Kerko
Beiträge: 334
Registriert: Mo 12. Aug 2013, 22:18

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Kerko »

Arduino Nano hat bei mir auch nicht funktioniert. Habe dann ein ESP2866 genommen und bin so wie im Video vorgegangen. Musste aber zwei mal flashen bis es geklappt hat. Stromversorgung habe ich über die 3,3V vom ESP Board gemacht.
Gary
Beiträge: 4214
Registriert: Mo 12. Aug 2013, 01:02

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Gary »

Von Hightech auf Seite 1

Info:
Nicht mit einem 5V Arduino flashen, damit killt man den Controller.
Wenn, dann die VCC auf 3,3V und die Datenleitungen mit einem Spannungsteiler an den Output Pins.
Besser einen ESP32 3,3V verwenden.
Benutzeravatar
ProgBernie
Beiträge: 305
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

Ich hab's mir diesmal einfach gemacht und gleich einen TI CC-Debugger-clone geholt. Von hier:

https://www.ebay.de/itm/372918614163

Hat mit der TI-Software ohne Probleme funktioniert.
caprivi
Beiträge: 484
Registriert: Mi 9. Mär 2016, 14:44
Wohnort: Am ehemaligen Schorbaer Berg.

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von caprivi »

Edith meint, hier stehen zu viele naive Fragen, und schlägt vor, gleich weiterzuscrollen.

Ich versuche gerade zu verstehen, was ich genau tun muss, um aus den Schildern eine billigen stromsparenden Arduino-ansteuerbaren Display zu machen. Die Doku bei Github scheint mir ein Bisschen für Leute, die schon tief in der Materie drin stecken und jede Menge implizit vorausgesetzten Hintergrund verstehen. Ich fremdele allgemein ein Bisschen mit dem Thema Programmierung, bin aber tapfer und will das hinbekommen. Ich versuch das also mal rückwärts aufzudröseln:

Als Display am Arduino (um in irgendeinem Sketch Grafiken zu malen oder Text zu schreiben) kann man offenbar diesen Sketch hier verwenden.
https://github.com/atc1441/E-Paper_Pric ... y_HINK.ino
Diese Quelle hier (https://github.com/atc1441/E-Paper_Pricetags) sagt zu unseren Preisschildern "...or use the "EinkSD_1.54_2.9_4.2_Standalone_Library_HINK" Arduino code to drive them." Das heisst, mit dem *.ino-Sketch müsste das gehen.

Frage: Wie/wo ist eigentlich der Font definiert, den ich hier bei "display.println("Was geht so");" angezeigt bekäme?

Noch eine Frage: Wenn ich den Arduino wie oben gleich auch benutzen möchte, um über die UART Text entgegenzunehmen und anzuzeigen (á la "serial.read() / display.println()"), wäre dann der gleiche Sketch geeignet? Dort gibt es ja das Statement "Serial.begin(115200);" für das ich ansonsten keine Verwendung sehe.

(Nebenfrage: Unter https://github.com/atc1441/ZBS_Flasher/ ... m-firmware findet man verschiedene Sketche, die mit UART... beginnen, aber ich vermute, das ist nicht für Text, sondern man muss dann dem Arduino, auf dem der Sketch läuft, ein Bild pixelweise über die Schnittstelle verfüttern? Ich sehe allerdings da kein Codebeispiel, wie man die Befüllung von aussen anschliessend praktisch handhaben würde. Hab ich das übersehen?)

Und schliesslich mal angenommen, ich müsste eine neue Firmware auf das Schild schreiben, dann ...
  • hätte ich noch keine Idee, welche Firmware ich bräuchte, um den Anzeige-Sketch von weiter oben nutzen zu können. Ich nehme an, dass ich das Preisschild vorher mit einer Firmware ausstatten muss, die die Benutzung des Skripts erlaubt ... korrekt?

Für die Programmierung des Preisschildes mit einer neuen Firmware müsste ich ein Programmiergerät (ein ESP32 oder ein Arduino nano) entsprechend dieser Zeichnung hier... https://github.com/atc1441/ZBS_Flasher/ ... pinout.jpg an das Display anschliessen und das *.bin-File auf das Preisschild laden.
Ich würde dabei gern den ESP32 und platform.io zum Programmieren des Programmieradapters vermeiden und in der Arduino-Welt bleiben, gibt es da einen Weg?
Ich sehe in der Grafik oben mehr Pins als die mir geläufigen ISP-Adapter haben. Werden hier tatsächlich mehr Anschlüsse gebraucht? Denn sonst müsste doch eigentlich jedes ISP-Programmiergerät funktionieren; es geht doch "nur" um die Übertragung eines *.bin-Files, oder bin ich hier falsch?
Zuletzt geändert von caprivi am Do 27. Okt 2022, 18:43, insgesamt 1-mal geändert.
caprivi
Beiträge: 484
Registriert: Mi 9. Mär 2016, 14:44
Wohnort: Am ehemaligen Schorbaer Berg.

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von caprivi »

Wuste ich's doch, hab noch was vergessen: Die Anschlüsse im Display-Sketch...

Code: Alles auswählen

// CLK 18
// MOSI 23
#define OLED_DC    17
#define OLED_CS    5
#define OLED_RESET 16
#define OLED_BUSY 4
EinkDisplay display(SPI, OLED_DC, OLED_RESET, OLED_CS, OLED_BUSY);
...finden sich nicht in dem Bild wieder, die den Anschluss des Programmieradapters beschreiben. Und andere Anschlüsse gibt es auf der Platine nicht.

Werden die Programmieranschlüsse nach dem Laden der neuen Firmware umgewidmet, oder müsste man dann direkt an den Flachbandverbinder ran?

Ich glaube, MSG hatte ganz zu Anfang des Fadens schon mal die gleiche Frage gestellt.
Benutzeravatar
Finger
Administrator
Beiträge: 6558
Registriert: Di 12. Jun 2012, 20:16
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Finger »

Station.py läuft jetzt auch, macht mir aber eine Fehlermeldung:

2022-10-25 20:57:08,982 Got checkin request
2022-10-25 20:57:08,983 CheckinInfo(swVer=1172526071808, hwType=8, batteryMv=2450, lastPacketLQI=83, lastPacketRSSI=203, temperature=150, rfu=b'\x00\x00\x00\x00\x00\x00')
2022-10-25 20:57:08,986 Reading image file:./000002855d4e3b14.bmp/.png
2022-10-25 20:57:08,988 Using .png file
2022-10-25 20:57:08,993 Unable to prepare image data for client [0, 0, 2, 133, 93, 78, 59, 20]
2022-10-25 20:57:08,994 [Errno 2] No such file or directory: '/tmp/tempConvert.bmp'
2022-10-25 20:57:08,996 Reading firmware file: UPDT0008.BIN
2022-10-25 20:57:08,997 No Firmware file available
2022-10-25 20:57:08,999 PendingInfo(imgUpdateVer=0, imgUpdateSize=0, osUpdateVer=0, osUpdateSize=0, nextCheckinDelay=0, rfu=bytearray(b'\x00\x00\x00\x00'))

Groß und Kleinschreibung beim Dateinamnen hat keinen Einfluß auf diese Meldung. Das Verzeichnis tmp\ existiert. Auflösung des Bildes sind 128x296px, senkrecht. Irfanview und Paint können die Datei öffnen. PNG oder BMP erzeugen das gleiche Problem. Was sagt mir denn das? Oder: an welcher Schraube muss ich denn da drehen?
manawyrm
Beiträge: 50
Registriert: Sa 3. Okt 2015, 23:09
Wohnort: Alfeld (Leine)
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von manawyrm »

Das Verzeichnis tmp\ existiert
'/tmp/tempConvert.bmp'
/tmp ist ein temporärer Ordner (und häufig eine RAM-Disk) auf Unix-ähnlichen Systemen. Pfade, die mit / anfangen sind absolute Pfadangaben.
Wenn du da zufällig gerade ein Windows oder ähnliches hast, wird der mit dem Pfad so gar nichts anfangen können und dann nie was sinnvolles machen.

Code: Alles auswählen

IMAGE_WORKDIR = os.environ.get("EPS_IMAGE_WORKDIR", default="/tmp/")
Ich würde also entweder als Umgebungsvariable EPS_IMAGE_WORKDIR oder einfach direkt im Code einen absoluten Pfad zu einem Ordner mit Schreibrechten übergeben und es so versuchen.

Der Code macht aber auch noch einige andere Sachen, wie die Pfadzusammensetzung und Serial-Port Geschichten, wo unter Windows evtl. noch das ein oder andere knirschen könnte.
/dev/ttyACM0 musst du dann vermutlich auch noch durch deinen COM* ersetzen.
Benutzeravatar
Finger
Administrator
Beiträge: 6558
Registriert: Di 12. Jun 2012, 20:16
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Finger »

Letztes hatte ich schon angepasst, die Tags sprechen ja auch mit dem Ding. Ich hab jetzt mal stumpf im Root \tmp\ angelegt. Mal schauen was das macht. Siehtse, das tuts tatsächlich. Danke für den Tip!
caprivi
Beiträge: 484
Registriert: Mi 9. Mär 2016, 14:44
Wohnort: Am ehemaligen Schorbaer Berg.

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von caprivi »

Ich hatte weiter oben einen Sack Fragen gestellt, weil ich der Annahme war, dass man die e-Ink-Displays recht unkompliziert auch als Ausgabemedium für kleinere Mikrocontrollerprojekte benutzen könnte.
Ich habe mich in den letzten Tagen etwas dazu belesen, und komme zum Schluss, dass das leider nicht der Fall ist.

Eine einfache Ansteuerung von e-Ink-Displays, z.B. als Low-Cost-Display-Alternative an einem Arduino ist aus zwei Gründen schwierig:

1. Man braucht genau bemessene Ansteuerungskurven für die e-Ink-Partikel mit positivem und negativem Vorzeichen, die i.d.R. auf die jeweiligen Displays und ihre Anatomie (schwarz/weiss oder dreifarbig) abgestimmt sind, weil die Physik hinter der gezielten Bewegung dieser z.T. unterschiedlich grossen, elektrisch geladenen Kullern im Ölbad recht tückisch ist. Eine sehr unterhaltsame Erklärung findet man hier (es lohnt sich aber oben anzufangen, um den Teil nicht zu verpassen, der sich mit der Informations- und Produktpolitik eines bestimmten Controllerherstellers beschäftigt. Ich hab mich sehr gekugelt. Jedenfalls - diese "waveforms" muss man kennen, sonst sieht man keine ordentlichen Bilder oder beschädigt im Extremfall sogar die Displays. Es gibt Bibliotheken, die diesen Teil übernehmen, zum Beispiel bei Adafruit oder - abgeleitet davon - bei Aaron Christophel.

2. Man hat den anzuzeigenden Pixeldatensatz idealerweise im RAM vorliegen. Viele Mikrocontroller haben aber nicht genug RAM, was bedeutet, dass man jedes anzuzeigende Bild zunächst im Flash speichern müsste, was die Lebensdauer der Controller beeinträchtigt. Das heisst, eine Lösung mit Raspi mag funktionieren, eine mit Arduino Uno vielleicht auch noch, eine Lösung mit Arduino Pro Mini wird nicht funktionieren. Und dieser Punkt ist am Ende das KO-Kriterium: Die Displays sind vom Datenaufwand her nicht mehr mit so was Kleinem wie ATTiny oder ATMega zu beherrschen.

Selbst wenn man diese Nachteile in Kauf nimmt, muss man die e-Ink-Displays an Adapterplatinen/Breakout-Boards hängen, die es z.B. bei Waveshare oder Adafuit gibt. Sie stellen die Spannungsquellen für die Ansteuerung und z.T. RAM zur Zwischenspeicherung bereit. Bei Waveshare gibt es ausserdem eine recht informative Seite zu Anschluss- und Ansteuerfragen; diese Angaben wird man z.B. brauchen, um die oben genannten Bibliotheken zur Ansteuerung zu nutzen. Schaut man sich aber die Preise dieser Adapterboards an, summiert sich alles recht schnell, und der ursprüngliche Vorteil, für zweifünfzig gewaschen und gekämmt zu sein ist dahin, und man kann auch gleich den "Umweg" über die jetzt hier im Faden etablierte Lösung mit Zigbee-Stick und Python-Skript gehen.
Benutzeravatar
Andreas_P
Beiträge: 1393
Registriert: Mo 12. Aug 2013, 11:35
Wohnort: Lohr am Main
Kontaktdaten:

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Andreas_P »

Letzte Woche am Freitag kam ein Päckchen mit einen vertrauten Klebeband von der Post.
Wie es zu erwarten war waren das die Preisschilder, danke Hightech dafür.
Nach dem dann unter der Woche Zigbee USB Stick, Adapterplatine und Pogo Pins eingetroffen sind, konnte ich am Mittwoch anfangen
die passende FW auf dem USB Stick zu übertragen. Mit Windows wolte das bei mir überhaupt nicht funktionieren.
Raspberry Pi und Linux lösten das Problem in kurzer Zeit. Leider hatte ich zu kurze Pogo Pins bestellt, also habe ich längere bestellt.

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 ?
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Man kann die Displays ohne weiteres ohne Adapter an einen ESP32 hängen, wenn man die Displayplatine von dem Controller befreit.
Die für das Display benötigten Spannungen werden von den Bauteilen auf der Platine erzeugt.
Dafür gibt es eine eigene Bibliothek.
Benutzeravatar
Bastelbruder
Beiträge: 10959
Registriert: Mi 14. Aug 2013, 18:28
Wohnort: drunt' am Neckar - km142,7

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Bastelbruder »

Es muß nicht unbedingt die ganze Bitmap im Ram liegen, Kompressionsalgorithmen wie RLC (Lauflängencodierung), speziell dynamisch angepaßter Code kann da durchaus noch etwas sparen.

Wenn man 1 byte in 2 bit Farbe und 6 bit Länge aufteilt, lassen sich bis zu 64 Pixel in einem byte verstecken. Und da gibt es sicher noch deutlich effektivere Varianten.
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Man kann einen EPS32 direkt dran hängen.
https://github.com/atc1441/E-Paper_Pric ... brary_HINK
Dazu habe ich den Controller herunter gelötet und die RFID-Antenne abgeschnitten.

Zu Beachten ist :
Es werden die Leitungen vom Display direkt an den ESP gelötet.
Die Signale SCL und SDA kommen am ESP an die Anschlüsse
SCL = SCK(4) und SDA = MOSI (6)
Die anderen Signale sind egal wo die dran kommen.

Pin 8 kommt schlicht an Masse.

Bild
https://cdn.sparkfun.com/assets/1/c/5/9 ... x128-n.pdf


#define OLED_DC 8
#define OLED_CS 5
#define OLED_RESET 10
#define OLED_BUSY 1
EinkDisplay display(SPI, OLED_DC, OLED_RESET, OLED_CS, OLED_BUSY);

Ich hab im Moment nur ein Problem mit dem CS Singal, das Display tut nur was, wenn ich einen 1M Widertstand am CS Pin habe....

Bild
Benutzeravatar
ProgBernie
Beiträge: 305
Registriert: Fr 16. Sep 2022, 21:59
Wohnort: Zwischen Hamburg und Haiti ^W Lübeck

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von ProgBernie »

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 ?
Nimm doch eines der vorhandenen STLs und schneide da nur den Bereich der Kontaktierung raus. In OpenScad ist das ein Dreizeiler.

Code: Alles auswählen

intersection() {
  translate([-6,48,0]) import("ZBS243_Pogo_Flasher_main_body.stl");
  cube([20,12,10]);
}
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

Da ich den Eindruck habe, das der Stick mir das WLAN zubrüllt mit Müll, hab ich den mal in Messing eingesperrt. .
53DBE93E-2149-4547-8846-E9F4F7271036.jpeg
Benutzeravatar
sukram
Beiträge: 2516
Registriert: Sa 10. Mär 2018, 18:27
Wohnort: Leibzsch

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von sukram »

Natürlich macht der das. Zigbee ist auch nur auf dem 2,4GHz ISM Band unterwegs. Man kann aber idR die Kanäle so legen, dass WLAN z.b. von Ch 5-13 liegt und Zigbee auf Ch 11. Es zählen die Kanalnummern noch mal anders, weil die weniger Bandbreite haben.

Hier was in neuhochplatt zum Thema: https://www.metageek.com/training/resou ... existence/
Benutzeravatar
Hightech
Beiträge: 9946
Registriert: So 11. Aug 2013, 18:37

Re: Elektronisches Preisschild Sammelbestellung - Ansteuerung

Beitrag von Hightech »

sukram hat geschrieben: Sa 29. Okt 2022, 12:12 Natürlich macht der das. Zigbee ist auch nur auf dem 2,4GHz ISM Band unterwegs. Man kann aber idR die Kanäle so legen, dass WLAN z.b. von Ch 5-13 liegt und Zigbee auf Ch 11. Es zählen die Kanalnummern noch mal anders, weil die weniger Bandbreite haben.

Hier was in neuhochplatt zum Thema: https://www.metageek.com/training/resou ... existence/
Ich meinte auch eher den E-Smog vom Controller und so. Wer weiss was der so an Schmutz außerhalb vom Kanal 11 macht.
Antworten