IOWP (IO-Warrior Python)

Stand: Dienstag 3. März 2026 - 0.1.3 - In Entwicklung! - mit macOS (Apple Silicon)

Einleitung

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 wink.
Dokumentation wird auf jeden Fall besser (github, PyPi und Web (diese Seite)).
Kommerziellen Support wird es auch geben.

Installation und Test

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:

  1. Regel-Datei erstellen:
sudo nano /etc/udev/rules.d/99-iowarrior.rules
  1. Diesen Inhalt hineinkopieren: (Dies erlaubt jedem Nutzer Lese- und Schreibzugriff auf IO-Warrior Geräte)
SUBSYSTEM=="usb", ATTRS{idVendor}=="07c0", MODE="0666" SUBSYSTEM=="iowarrior", MODE="0666"

Beispiele (mindestens iowp 0.1.2)

LCD Beispiel 1:

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

LCD Beispiel 2:

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

LCD Beispiel 3:

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

LCD Beispiel 4:

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

LCD Beispiel 5:

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

IOWP is still under development!

© 2026 by Thomas Wagner, Mail: thomas@wagner-ibw.de (aktuallisiert: 03.03.2026)