Page 1 of 1

GPIO with docker

Posted: Tuesday 15 April 2025 16:21
by solarboy
I have been trying to follow the GPIO guide on the wiki, however I tried installing "generic sysfs GPIO" but no devices were created. I tried using the command
echo 11 > /sys/class/gpio/export
but got this error
-bash: echo: write error: Invalid argument
At this point I tried the second method however it appears wiringpi is no longer available.
Unable to locate package wiringPi
Is there any way to get this working ?

Re: GPIO with docker

Posted: Tuesday 15 April 2025 16:42
by waltervl
A quick search on the forum gave me this: viewtopic.php?p=311392#p311392

Re: GPIO with docker

Posted: Tuesday 15 April 2025 18:44
by solarboy
Thanks walter, I managed to get something working with a python gpio2mqttAD script, still a work in progress but functional.

Code: Select all

import paho.mqtt.client as mqtt
import RPi.GPIO as GPIO
import time
import json

# GPIO setup
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

# Define relay GPIO pins (BCM numbering)
RELAY_PINS = [17, 27, 22, 23]  # Pin 23 = GPIO23 (Physical 16)
for pin in RELAY_PINS:
    GPIO.setup(pin, GPIO.OUT)
    GPIO.output(pin, GPIO.HIGH)  # Inverted logic: HIGH = OFF (for active low relays)

# MQTT settings
MQTT_BROKER = "localhost"  # Address of your MQTT broker (e.g., localhost or IP)
MQTT_PORT = 1883
MQTT_TOPIC_PREFIX = "domoticzSolar"
MQTT_DISCOVERY_PREFIX = "homeassistant/switch"  # Home Assistant discovery style

# MQTT client setup
mqtt_client = mqtt.Client()

# Function to generate a unique ID based on GPIO pin
def get_unique_id(pin):
    return f"gpio-relay-board-{pin}"

def on_connect(client, userdata, flags, rc):
    print(f"Connected to MQTT broker with result code {rc}")

    # Send discovery message for each relay (only once)
    for i, pin in enumerate(RELAY_PINS, start=1):
        relay_name = f"Relay {i}"
        relay_id = f"relay{i}"
        unique_id = get_unique_id(pin)  # Static unique ID based on GPIO pin

        # Prepare the MQTT discovery payload
        discovery_payload = {
            "name": relay_name,
            "command_topic": f"{MQTT_TOPIC_PREFIX}/{relay_id}/set",
            "state_topic": f"{MQTT_TOPIC_PREFIX}/{relay_id}/state",
            "payload_on": "ON",
            "payload_off": "OFF",
            "state_on": "ON",
            "state_off": "OFF",
            "retain": True,  # Ensure the configuration persists after restart
            "unique_id": unique_id,
            "device": {
                "identifiers": [unique_id],  # Device identifier as unique_id
                "name": "GPIO Relay Board",
                "model": "Pi GPIO",
                "manufacturer": "YourName"
            },
            "device_class": "switch"
        }

        # Send the discovery message to the broker only once
        discovery_topic = f"{MQTT_DISCOVERY_PREFIX}/gpio-relay-board-{pin}/config"
        mqtt_client.publish(discovery_topic, json.dumps(discovery_payload), retain=True)
        print(f"Published MQTT discovery message for {relay_name} with unique_id {unique_id}")

def on_message(client, userdata, msg):
    topic_parts = msg.topic.split("/")
    if len(topic_parts) < 3:
        return

    relay_name = topic_parts[1]
    if relay_name.startswith("relay"):
        try:
            relay_num = int(relay_name[5:])
            if 1 <= relay_num <= len(RELAY_PINS):
                if msg.payload.decode() == "ON":
                    GPIO.output(RELAY_PINS[relay_num - 1], GPIO.LOW)  # Inverted logic
                    mqtt_client.publish(f"{MQTT_TOPIC_PREFIX}/{relay_name}/state", "ON", retain=True)
                elif msg.payload.decode() == "OFF":
                    GPIO.output(RELAY_PINS[relay_num - 1], GPIO.HIGH)  # Inverted logic
                    mqtt_client.publish(f"{MQTT_TOPIC_PREFIX}/{relay_name}/state", "OFF", retain=True)
        except ValueError:
            print(f"Invalid relay number: {relay_name}")

def run_gpio_mqtt():
    mqtt_client.on_connect = on_connect
    mqtt_client.on_message = on_message

    mqtt_client.connect(MQTT_BROKER, MQTT_PORT, 60)

    mqtt_client.loop_start()

    # Subscribe to relay control topics
    for i in range(1, len(RELAY_PINS) + 1):
        mqtt_client.subscribe(f"{MQTT_TOPIC_PREFIX}/relay{i}/set")

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Shutting down...")
        GPIO.cleanup()
        mqtt_client.disconnect()

if __name__ == "__main__":
    run_gpio_mqtt()
I have to disable device creation as the domoticz creates new devices on each start, but it does work. Need to work on the auto discovery stuff.

Re: GPIO with docker

Posted: Tuesday 15 April 2025 19:51
by solarboy
Is there any reason new devices created on the slave aren't visible on the main Domoticz instance ? I have a previously set up test virtual switch that is working so the basic connection is fine but new devices aren't appearing. I have "allow new devices" enabled and I have tried starting and stopping the "Domoticz Remote Server" hardware.

Re: GPIO with docker

Posted: Tuesday 15 April 2025 20:58
by waltervl
When using remote device sharing you have to open up the sharing port (default 6144) in the docker image configuration.

Re: GPIO with docker

Posted: Tuesday 15 April 2025 23:02
by solarboy
Yeah, did that and it was working before and created a test virtual device which still works.

Code: Select all

services:
  domoticz:
    image: domoticz/domoticz:stable
    container_name: domoticz
    restart: unless-stopped
    # Pass devices to container
    # devices:
    #   - "/dev/serial/by-id/usb-0658_0200-if00-port0:/dev/ttyACM0"
    ports:
      - "8080:8080"
      - "6144:6144"
    volumes:
      - ./config:/opt/domoticz/userdata
      #- ./config/www/templates:/opt/domoticz/www/templates
    environment:
      - TZ=Europe/Lisbon
      #- LOG_PATH=/opt/domoticz/userdata/domoticz.log
However new devices arent being created, neither another identical virtual switch or some MQTT Discovery Devices I have on the slave.

Re: GPIO with docker

Posted: Wednesday 16 April 2025 10:36
by waltervl
Nothing in the logs about remote sharing?

From the wiki
Data is pushed to the Main from the Remote triggered by device changes. So if a device changes it will be synchronised.
It would be wise to check the "Setup | Log" to double check there are no errors.

Re: GPIO with docker

Posted: Wednesday 16 April 2025 11:27
by solarboy
Nothing in the logs but while I was asleep the solution came to me ; the newer devices needed to be added in "Set Devices" as they didn't exist when I created the remote user.

Thanks for your help Walter.

Re: GPIO with docker

Posted: Wednesday 16 April 2025 21:44
by akamming
You are describing a very difficult solution.

Just google on “docker gpio Access raspberry pi” and you get several articles describing solutions.

The most easy one is running the docker container in privileged mode..