Stand: Dienstag 3. März 2026 - 0.1.3 - In Entwicklung! - mit macOS (Apple Silicon)
IOWJ ist tot, es lebe IOWP!
Was war noch mal IOWJ?
Alle Iow-Features in Java-Klassen packen und mehrere special mode functions in mehreren Iow's gleichzeitig benutzen, Events bei Pin-Eingabe.
Und: Write once, run anywhere: dem Program sollte egal sein, was für ein Iow benutzt wird (natürlich nur, wenn das technisch auch möglich ist).
Das sollte auch für die Betriebssysteme gelten. MacOS war aber leider draußen, weil es keine iowkit Lib gab.
Was ist nun IOWP?
Das ist der Phyton Port von IOWJ, aber: inklusive MacOS! Aus Kompatibilitätgründen ist auch hier iowkit.py die Basis.
Wer sich also mit den Reports selber herumärgern will, kann das immer noch gerne tun. Aus meiner Sicht sind aber in der Vergangenheit viele potentielle Nutzer (Bastler)
an diesen Reports gescheitert, weil man für deren richtige Anwendung Datenblätter lesen muss .
Dokumentation wird auf jeden Fall besser (github, PyPi und Web (diese Seite)).
Kommerziellen Support wird es auch geben.
Voraussetzugen: Installiertes Python3, und wenn man das Repository clonen möchte (optional), git.
Ein neues Arbeitsverzeichnis erstellen:
mkdir test_iow
cd test_iowp
Optional: Git Repository clonen (wenn man die Beispiele nicht einzeln abtippen oder herunterladen möchte).
Achtung: git clone funktioniert nur in eine leeres Verzeichns!
git clone https://github.com/3zxpo/iowp.git .
Ich empfehle, das virtuelle Environment von Python zu benutzen. venv einrichten:
python3 -m venv .venv
venv aktivieren:
source ./venv/bin/activate
iowp installieren (im venv!):
pip install iowp
Neue Versiom von iowp installieren (im venv!):
pip install --upgrade iowp
Installierte Version von iowp anzeigen (im venv!):
python -c "import iowp; print(iowp.__version__)"
Angeschlossene Iow's anzeigen (im venv!):
python -m iowp
Number of plugged IO-Warrior device(s): 1
Device 0: IOW100 (Serial: 00000236, Rev: 0x1018)
Beispiel 2 ausprobieren (im venv!)
Hardware: Iow24 Dongle und ein 2x16 LCD mit montiertem I2C-Modul-PCF8574 miteinander koppeln:
gleichnamige Anschlüsse sind miteinander zu verbinden: GND, VCC, SDA, SCL.
python test_iowp_i2clcd_short.py
Anmerkung: auch wenn die ständige Erwähnung des venv vielleicht genervt hat:
Man muss es nur einmal einrichten aber jedes mal aktivieren, wenn man den Rechner
neu gestartet hat. Das man es aktiviert hat, ermennt man daran, dass der
Konsolenprompt mit "(.venv)" beginnt (siehe nächster Kasten 'Windows').
Hier dieselben Schritte unter Windows (Benutzers xxx):
C:\Users\xxx\>mkdir test_iowp
C:\Users\xxx\>cd test_iowp
C:\Users\xxx\test_iowp>git clone https://github.com/3zxpo/iowp.git .
C:\Users\xxx\test_iowp>python -m venv .venv
C:\Users\xxx\test_iowp>.venv\Scripts\activate
(.venv) C:\Users\xxx\test_iowp>pip install iowp
(.venv) C:\Users\xxx\test_iowp>pip install --upgrade iowp
(.venv) C:\Users\xxx\test_iowp>python -c "import iowp; print(iowp.__version__)"
0.1.3
(.venv) C:\Users\xxx\test_iowp>python -m iowp
Number of plugged IO-Warrior device(s):
Device 0: IOW24 (Serial: 00000009), Rev: 0x1029)
(.venv) C:\Users\xxx\test_iowp>python test_iowp_i2clcd_short.py
Hier dieselben Schritte unter Linux:
mkdir test_iowp
cd test_iowp
git clone https://github.com/3zxpo/iowp.git .
python -m venv .venv
source .venv\bin\activate
pip install iowp
pip install --upgrade iowp
python -c "import iowp; print(iowp.__version__)"
0.1.3
sudo .venv/bin/python -m iowp
Number of plugged IO-Warrior device(s):
Device 0: IOW24 (Serial: 00000009), Rev: 0x1029)
sudo .venv/bin/python test_iowp_i2clcd_short.py
Standardmäßig können die USB Geräte nur als root benutzt weren. Um das zu ändern, ist die Erstellung folgender Datei notwendig:
sudo nano /etc/udev/rules.d/99-iowarrior.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="07c0", MODE="0666"
SUBSYSTEM=="iowarrior", MODE="0666"
(Nutzt die LCD special mode function eines beliebigen Iow (24,28,40,56 und 100) und gibt einfachen Text und ein benutzerdefiniertes Zeichen aus.)
Achtung: bei mir funktioniert zur Zeit das Programm erst ab dem zweiten Programmstart!
from iowp.factory import IowFactory
from iowp.lcd import LCD2x16
def main():
factory = IowFactory.get_instance()
if len(factory.get_devices()) == 0:
print("No IO-Warrior devices found.")
return
iow_dev = factory.get_iow_device(0)
lcd = LCD2x16()
iow_dev.add_special_mode_function_impl(lcd)
print(iow_dev)
try:
print("Clearing LCD...")
lcd.clear_lcd()
print("Writing lines...")
lcd.write_line(1, True, "Hello iowp!")
lcd.write_line(2, True, "LCD 2x16 Ready")
print("Testing special characters (smiley)...")
smiley = [
0b00000,
0b01010,
0b01010,
0b00000,
0b10001,
0b01110,
0b00000,
0b00000
]
lcd.set_special_char(0, smiley)
lcd.set_cursor(1, 16)
lcd.write_string(chr(0))
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()
Dazu passender Terminal Output (mit angeschlossenem Iow28):
IOW28:Handle[4307557680],Id[5380],Rev[0x100b],Serial[00000243],Listener[0],SpecialMode: LCD
P0[IoMask[SSSSIIII],Data[XXXX1111],Listener[0]]
P1[IoMask[SSSSSSSS],Data[XXXXXXXX],Listener[0]]
P2[IoMask[......II],Data[......11],Listener[0]]
P3[IoMask[I.......],Data[1.......],Listener[0]]
Clearing LCD...
Writing lines...
Testing special characters (smiley)...
(Nutzt die I2C special mode function eines beliebigen Iow (24,28,40,56 und 100) und das I2C Device I2CLCD (I2C / TWI-Schnittstellenmodul Serial PCF8574T für 1602 LCD) um einfachen Text und ein benutzerdefiniertes Zeichen auszugeben.)
from iowp import IowFactory, I2C
from iowp.i2c_devices import I2CLCD
def main():
factory = IowFactory.get_instance()
if len(factory.get_devices()) == 0:
print("No IO-Warrior devices found.")
return
iow_dev = factory.get_iow_device(0)
i2c = I2C(I2C.I2C_SPEED_100KHZ)
iow_dev.add_special_mode_function_impl(i2c)
lcd = I2CLCD(device_address=0x07, rows=2, cols=16)
i2c.add_i2c_device(lcd)
print(iow_dev)
try:
print("Clearing LCD...")
lcd.clearLCD()
print("Writing lines...")
lcd.setCursor(0, 0)
lcd.writeString("Hello iowp")
lcd.setCursor(1, 0)
lcd.writeString("LCD 2x16 Ready")
print("Testing special characters (smiley)...")
smiley = [
0b00000,
0b01010,
0b01010,
0b00000,
0b10001,
0b01110,
0b00000,
0b00000
]
lcd.createChar(0, smiley)
lcd.setCursor(0, 15)
lcd.writeString(chr(0))
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()
Dazu passender Termial Output (mit angeschlossenem Iow24):
IOW24:Handle[4299742512],Id[5377],Rev[0x1029],Serial[00000009],Listener[0],SpecialMode: I2C
P0[IoMask[IIIIISSI],Data[11111XX1],Listener[0]]
P1[IoMask[IIIIIIII],Data[11111111],Listener[0]]
Clearing LCD...
Writing lines...
Testing special characters (smiley)...
(Kombiniert Beispiel 1 und Beispiel 2.
Die Mehoden der beiden LCD-Objekte sind noch aus historischen Gründen unterschiedlich, was eigentlich keine Sinn ergibt und noch geändert wird.)
from iowp import IowFactory, I2C
from iowp.i2c_devices import I2CLCD
from iowp.lcd import LCD2x16
def main():
factory = IowFactory.get_instance()
if len(factory.get_devices()) == 0:
print("No IO-Warrior devices found.")
return
print(factory)
# Iow28, SMF LCD and LCD2x16
iow_dev_28 = factory.get_iow28_device()
lcd_28 = LCD2x16()
iow_dev_28.add_special_mode_function_impl(lcd_28)
print(iow_dev_28)
# Iow24, SMF I2C and i2clcd (PCF8547 based LcD)
iow_dev_24 = factory.get_iow24_device()
i2c = I2C(I2C.I2C_SPEED_100KHZ)
iow_dev_24.add_special_mode_function_impl(i2c)
lcd_24 = I2CLCD(device_address=0x07, rows=2, cols=16)
i2c.add_i2c_device(lcd_24)
print(iow_dev_24)
try:
print("Clearing LCD...")
lcd_28.clear_lcd()
lcd_24.clearLCD()
print("Writing lines...")
lcd_28.write_line(1, True, "Hello iowp! (28)")
lcd_28.write_line(2, True, "LCD 2x16 Ready")
lcd_24.setCursor(0, 0)
lcd_24.writeString("Hello iowp! (24)")
lcd_24.setCursor(1, 0)
lcd_24.writeString("LCD 2x16 Ready")
print("Testing special characters (smiley)...")
smiley = [
0b00000,
0b01010,
0b01010,
0b00000,
0b10001,
0b01110,
0b00000,
0b00000
]
lcd_28.set_special_char(0, smiley)
lcd_28.set_cursor(2, 16)
lcd_28.write_string(chr(0))
lcd_24.createChar(0, smiley)
lcd_24.setCursor(1, 15)
lcd_24.writeString(chr(0))
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()
Dazu passender Termial Output (mit angeschlossenen Iow24 und Iow28):
Number of plugged IO-Warrior device(s): 2
Device0: IOW24:Handle[4333805856],Id[5377],Rev[0x1029],Serial[00000009],Listener[0],SpecialMode:
P0[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P1[IoMask[IIIIIIII],Data[11111111],Listener[0]]
Device1: IOW28:Handle[4333529808],Id[5380],Rev[0x100b],Serial[00000243],Listener[0],SpecialMode:
P0[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P1[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P2[IoMask[......II],Data[......11],Listener[0]]
P3[IoMask[I.......],Data[1.......],Listener[0]]
IOW28:Handle[4333529808],Id[5380],Rev[0x100b],Serial[00000243],Listener[0],SpecialMode: LCD
P0[IoMask[SSSSIIII],Data[XXXX1111],Listener[0]]
P1[IoMask[SSSSSSSS],Data[XXXXXXXX],Listener[0]]
P2[IoMask[......II],Data[......11],Listener[0]]
P3[IoMask[I.......],Data[1.......],Listener[0]]
IOW24:Handle[4333805856],Id[5377],Rev[0x1029],Serial[00000009],Listener[0],SpecialMode: I2C
P0[IoMask[IIIIISSI],Data[11111XX1],Listener[0]]
P1[IoMask[IIIIIIII],Data[11111111],Listener[0]]
Clearing LCD...
Writing lines...
Testing special characters (smiley)...
(Zwei mal Beispiel 2)
from iowp import IowFactory, I2C
from iowp.i2c_devices import I2CLCD
def main():
factory = IowFactory.get_instance()
if len(factory.get_devices()) == 0:
print("No IO-Warrior devices found.")
return
print(factory)
# Iow 1, SMF I2C and i2clcd (PCF8547 based LcD)
iow_dev_1 = factory.get_iow_device(0)
i2c_1 = I2C(I2C.I2C_SPEED_100KHZ)
iow_dev_1.add_special_mode_function_impl(i2c_1)
lcd_1 = I2CLCD(device_address=0x07, rows=2, cols=16)
i2c_1.add_i2c_device(lcd_1)
print(iow_dev_1)
# Iow 2, SMF I2C and i2clcd (PCF8547 based LcD)
iow_dev_2 = factory.get_iow_device(1)
i2c_2 = I2C(I2C.I2C_SPEED_100KHZ)
iow_dev_2.add_special_mode_function_impl(i2c_2)
lcd_2 = I2CLCD(device_address=0x07, rows=2, cols=16)
i2c_2.add_i2c_device(lcd_2)
print(iow_dev_2)
try:
print("Clearing LCD...")
lcd_1.clearLCD()
lcd_2.clearLCD()
print("Writing lines...")
lcd_1.setCursor(0, 0)
lcd_1.writeString("Hello iowp ")
lcd_1.writeString(iow_dev_1.name)
lcd_1.setCursor(1, 0)
lcd_1.writeString("LCD 2x16 Ready")
lcd_2.setCursor(0, 0)
lcd_2.writeString("Hello iowp ")
lcd_2.writeString(iow_dev_2.name)
lcd_2.setCursor(1, 0)
lcd_2.writeString("LCD 2x16 Ready")
print("Testing special characters (smiley)...")
smiley = [
0b00000,
0b01010,
0b01010,
0b00000,
0b10001,
0b01110,
0b00000,
0b00000
]
lcd_1.createChar(0, smiley)
lcd_1.setCursor(1, 15)
lcd_1.writeString(chr(0))
lcd_2.createChar(0, smiley)
lcd_2.setCursor(1, 15)
lcd_2.writeString(chr(0))
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
main()
Dazu passender Termial Output (mit angeschlossenen Iow24 und Iow56, die Reihenfolge ist nicht vorhersehbar):
Number of plugged IO-Warrior device(s): 2
Device0: IOW56:Handle[4311368096],Id[5379],Rev[0x2001],Serial[10003856],Listener[0],SpecialMode:
P0[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P1[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P2[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P3[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P4[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P5[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P6[IoMask[IIIIIIII],Data[11111111],Listener[0]]
Device1: IOW24:Handle[4308892432],Id[5377],Rev[0x1029],Serial[00000009],Listener[0],SpecialMode:
P0[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P1[IoMask[IIIIIIII],Data[11111111],Listener[0]]
IOW56:Handle[4311368096],Id[5379],Rev[0x2001],Serial[10003856],Listener[0],SpecialMode: I2C
P0[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P1[IoMask[SISIIIII],Data[X1X11111],Listener[0]]
P2[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P3[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P4[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P5[IoMask[IIIIIIII],Data[11111111],Listener[0]]
P6[IoMask[IIIIIIII],Data[11111111],Listener[0]]
IOW24:Handle[4308892432],Id[5377],Rev[0x1029],Serial[00000009],Listener[0],SpecialMode: I2C
P0[IoMask[IIIIISSI],Data[11111XX1],Listener[0]]
P1[IoMask[IIIIIIII],Data[11111111],Listener[0]]
Clearing LCD...
Writing lines...
Testing special characters (smiley)...
Bei den Ports (hier P0 bis P6) kann man schön sehen, welche Funktion die Bits haben und welcher Pegel anliegt:
IoMask (Richtung der Datenpins):
I - Input (Eingang)
O - Output (Ausgang)
S - Special (ein durch eine special mode function bemutztes Pin)
. - nicht existent
(links ist Pin7, rechts ist Pin 0)
Data (Pin Status):
1 - High
0 - Low
X - ubekannt, wird durch eine special mode funtion bestimmt
(links ist Pin7, rechts ist Pin 0)
(Wie Beispiel 4, aber die Ausgaben erfolgen nicht nacheinander, sondern gleichzeitig. Jetzt ist der Performancevorteil eines Iow56 gegenüber einem Iow24 deutlich sichtbar.)
import threading
from iowp import IowFactory, I2C
from iowp.i2c_devices import I2CLCD
# Die gekapselte Methode für die LCD-Ausgabe
def update_lcd(lcd, device_name):
try:
print(f"Starting update for {device_name}...")
# 1. LCD löschen
lcd.clearLCD()
# 2. Text schreiben
lcd.setCursor(0, 0)
lcd.writeString(f"Hello iowp ")
lcd.writeString(device_name)
lcd.setCursor(1, 0)
lcd.writeString("LCD 2x16 Ready")
# 3. Sonderzeichen (Smiley) erstellen und schreiben
smiley = [
0b00000,
0b01010,
0b01010,
0b00000,
0b10001,
0b01110,
0b00000,
0b00000
]
lcd.createChar(0, smiley)
lcd.setCursor(1, 15)
lcd.writeString(chr(0))
print(f"Finished update for {device_name}.")
except Exception as e:
print(f"Error on {device_name}: {e}")
def main():
factory = IowFactory.get_instance()
if len(factory.get_devices()) < 2:
print("Not enough IO-Warrior devices found. Need at least 2.")
return
# --- Setup Device 1 ---
iow_dev_1 = factory.get_iow_device(0)
i2c_1 = I2C(I2C.I2C_SPEED_100KHZ)
iow_dev_1.add_special_mode_function_impl(i2c_1)
lcd_1 = I2CLCD(device_address=0x07, rows=2, cols=16)
i2c_1.add_i2c_device(lcd_1)
# --- Setup Device 2 ---
iow_dev_2 = factory.get_iow_device(1)
i2c_2 = I2C(I2C.I2C_SPEED_100KHZ)
iow_dev_2.add_special_mode_function_impl(i2c_2)
lcd_2 = I2CLCD(device_address=0x07, rows=2, cols=16)
i2c_2.add_i2c_device(lcd_2)
# --- Threads erstellen ---
# Wir übergeben die LCD-Instanz und den Namen als Argumente (args)
thread1 = threading.Thread(target=update_lcd, args=(lcd_1, iow_dev_1.name))
thread2 = threading.Thread(target=update_lcd, args=(lcd_2, iow_dev_2.name))
# Threads starten (laufen jetzt parallel)
thread1.start()
thread2.start()
# Warten, bis beide fertig sind
thread1.join()
thread2.join()
print("Both LCDs updated simultaneously.")
if __name__ == "__main__":
main()
Dazu passender Termial Output (mit angeschlossenen Iow24 und Iow56, die Reihenfolge ist nicht vorhersehbar):
Starting update for IOW56...
Starting update for IOW24...
Finished update for IOW56.
Finished update for IOW24.
Both LCDs updated simultaneously.
Ich danke der Firma Code Mercenaries Hard- und Software GmbH für die langjährige und kostenlose Bereitstellung von Chips/Modulen/Starter Kits/Dongles
der verscheidensten IO-Warrior Typen. Ohne diese wäre die Entwicklung von IOWJ und IOWP nicht möglich gewesen. Venceremos!
© 2026 by Thomas Wagner, Mail: thomas@wagner-ibw.de (aktuallisiert: 03.03.2026)