Installation NRX800 / Home Assistant

Bonjour,
merci pour vos tests :clap: . Je souhaite également installer HA sur un NRX800, je suis donc ce post avec attention.
Bon courage !

Bon on avance

Déjà les commandes pour installer

# Créer le dossier de configuration
mkdir -p "/home/$USER/docker/home-assistant/config"

# Vérifier les permissions
sudo chown -R $USER:$USER "/home/$USER/docker/"

# On peut changer le nom de la clé si c'est une conbee
KeyName="*Sonoff*" 

sudo docker run -d --name home-assistant --restart unless-stopped --network=host --privileged -v "/home/$USER/docker/home-assistant/config:/config" --device "$(find /dev/serial/by-id/ -name "$KeyName" -type l | head -n1):/dev/ttyUSB0" -v /sys:/sys -v /proc:/proc -v /dev:/dev homeassistant/home-assistant:latest

Une fois installé…plus de add-ons !! HA se referme visiblement vers un modèles purement commercial…les gens apprécieront …ou pas !

Et si on essaie d’installer HACS comme indiqué plus haut

Donc plus d’installation de HACS (les dev apprécieront)

On passe par « Appareils et service »

On installe ZHA

Les appareils sont automatiquement détectés

Les GPIO après avoir modifié le configuration.yaml


Bah ca marches pas galère

Contournement installer Mosquitto et MQTT puis un script python pour gérer les GPIO

Mosquitto via HA bah…il y a plus !!!

On crée ce script pour installer le container Mosquitto
Il faut modifier le nom utilisateur et le mot de passe si ils sont différents

en SSH :

sudo nano ins-mosquitto.sh

et on colle le contenu suivant

ins-mosquitto.sh

#!/bin/bash
set -e

USER=« nrx800 »
PASS=« gce »
PASSFILE=« /etc/mosquitto/passwd »

echo « [*] Mise à jour et installation de Mosquitto… »
sudo apt update
sudo apt install -y mosquitto mosquitto-clients

echo « [*] Création du fichier de mots de passe… »
sudo mosquitto_passwd -c -b « $PASSFILE » « $USER » « $PASS »

echo « [*] Configuration Mosquitto pour activer l’authentification… »
CONF_FILE=« /etc/mosquitto/conf.d/auth.conf »
sudo bash -c « cat > $CONF_FILE <<EOF
allow_anonymous false
password_file $PASSFILE
listener 1883
EOF »

echo « [*] Redémarrage du service Mosquitto… »
sudo systemctl restart mosquitto
sudo systemctl enable mosquitto

echo « [*] Installation terminée. »
echo « ➡ Test rapide : »
echo " mosquitto_sub -h localhost -t test -u $USER -P $PASS &"
echo " mosquitto_pub -h localhost -t test -m ‹ hello › -u $USER -P $PASS"

en SSH on lance l’installation

sudo bash ins-mosquitto.sh

puis on installe MQTT

On sélectionne MQTT

en SSH on crée ce script pour gérer les gpio en mqtt (fait par IA) :

sudo nano ~/nrx-gpio.py

et on colle

nrx-gpio.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt
import RPi.GPIO as GPIO
import json
import time
import logging
from threading import Thread

# Configuration des broches GPIO selon votre configuration
RELAY_PINS = {
    1: 4,    # RLY 1 => GPIO 04 => Pin 7
    2: 5,    # RLY 2 => GPIO 05 => Pin 29
    3: 6,    # RLY 3 => GPIO 06 => Pin 31
    4: 12,   # RLY 4 => GPIO 12 => Pin 32
    5: 13,   # RLY 5 => GPIO 13 => Pin 33
    6: 16,   # RLY 6 => GPIO 16 => Pin 36
    7: 17,   # RLY 7 => GPIO 17 => Pin 11
    8: 18    # RLY 8 => GPIO 18 => Pin 12
}

INPUT_PINS = {
    1: 20,   # INPUT 1 => GPIO 20 => Pin 38
    2: 21,   # INPUT 2 => GPIO 21 => Pin 40
    3: 22,   # INPUT 3 => GPIO 22 => Pin 15
    4: 23,   # INPUT 4 => GPIO 23 => Pin 16
    5: 24,   # INPUT 5 => GPIO 24 => Pin 18
    6: 25,   # INPUT 6 => GPIO 25 => Pin 22
    7: 26,   # INPUT 7 => GPIO 26 => Pin 37
    8: 27    # INPUT 8 => GPIO 27 => Pin 13
}

LED_PIN = 19  # User Led = > GPIO 19 => Pin 35

# Configuration MQTT
MQTT_BROKER = "localhost"
MQTT_PORT = 1883
MQTT_USERNAME = "votre_nom_utilisateur"   # Remplacez par votre identifiant
MQTT_PASSWORD = "votre_mot_de_passe"      # Remplacez par votre mot de passe

# Nouveaux topics MQTT
MQTT_TOPIC_RELAY_SET = "nrx800/relay/{}/set"
MQTT_TOPIC_RELAY_STATE = "nrx800/relay/{}/state"
MQTT_TOPIC_INPUT_STATE = "nrx800/input/{}/state"
MQTT_TOPIC_LED_SET = "nrx800/led/set"
MQTT_TOPIC_LED_STATE = "nrx800/led/state"
MQTT_TOPIC_STATUS = "nrx800/status"

# État des relais et entrées
relay_states = {}
input_states = {}
led_state = False

# Configuration du logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

def gpio_setup():
    """Initialisation des GPIO"""
    try:
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BCM)  # Utilisation de la numérotation BCM
        
        # Configuration des relais en sortie
        for relay_id, pin in RELAY_PINS.items():
            GPIO.setup(pin, GPIO.OUT)
            GPIO.output(pin, GPIO.LOW)  # Désactivé par défaut
            relay_states[relay_id] = False
            logger.info(f"Relais {relay_id} initialisé sur GPIO {pin}")
        
        # Configuration des entrées avec pull-up
        for input_id, pin in INPUT_PINS.items():
            GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
            input_states[input_id] = GPIO.input(pin)
            logger.info(f"Entrée {input_id} initialisée sur GPIO {pin}")
        
        # Configuration de la LED
        GPIO.setup(LED_PIN, GPIO.OUT)
        GPIO.output(LED_PIN, GPIO.LOW)
        logger.info(f"LED utilisateur initialisée sur GPIO {LED_PIN}")
        
        return True
    except Exception as e:
        logger.error(f"Erreur initialisation GPIO: {e}")
        return False

def on_connect(client, userdata, flags, rc):
    """Callback appelée lors de la connexion au broker MQTT"""
    
    if rc == 0:
        logger.info("Connecté au broker MQTT avec succès")
        
        # Publication du statut "online"
        client.publish(MQTT_TOPIC_STATUS, "online", retain=True)
        logger.info(f"Statut publié: {MQTT_TOPIC_STATUS} -> online")
        
        # Abonnement aux topics de commande
        for relay_id in RELAY_PINS.keys():
            topic = MQTT_TOPIC_RELAY_SET.format(relay_id)
            client.subscribe(topic)
            logger.info(f"Abonné au topic: {topic}")
        
        client.subscribe(MQTT_TOPIC_LED_SET)
        logger.info(f"Abonné au topic: {MQTT_TOPIC_LED_SET}")
        
        # Publication des états initiaux
        publish_initial_states(client)
        
    elif rc == 5:
        logger.error("Erreur d'authentification : nom d'utilisateur ou mot de passe invalide.")
        # Publication du statut "authentication_error"
        client.publish(MQTT_TOPIC_STATUS, "authentication_error", retain=True)
    else:
        logger.error(f"Échec de connexion au broker MQTT, code: {rc}")
        # Publication du statut "connection_error"
        client.publish(MQTT_TOPIC_STATUS, f"connection_error_{rc}", retain=True)

def on_disconnect(client, userdata, rc):
    """Callback appelée lors de la déconnexion du broker MQTT"""
    if rc != 0:
        logger.warning("Déconnexion inattendue du broker MQTT")
    else:
        logger.info("Déconnexion normale du broker MQTT")
    
    # Publication du statut "offline" (si possible)
    try:
        client.publish(MQTT_TOPIC_STATUS, "offline", retain=True)
        logger.info(f"Statut publié: {MQTT_TOPIC_STATUS} -> offline")
    except Exception as e:
        logger.error(f"Impossible de publier le statut offline: {e}")

def on_message(client, userdata, msg):
    """Callback appelée à la réception d'un message MQTT"""
    try:
        payload = msg.payload.decode('utf-8')
        logger.info(f"Message reçu: {msg.topic} -> {payload}")
        
        # Commande pour les relais
        for relay_id in RELAY_PINS.keys():
            if msg.topic == MQTT_TOPIC_RELAY_SET.format(relay_id):
                handle_relay_command(client, relay_id, payload)
                return
        
        # Commande pour la LED
        if msg.topic == MQTT_TOPIC_LED_SET:
            handle_led_command(client, payload)
            
    except Exception as e:
        logger.error(f"Erreur lors du traitement du message: {e}")

def handle_relay_command(client, relay_id, payload):
    """Gestion des commandes pour les relais"""
    try:
        pin = RELAY_PINS[relay_id]
        
        if payload.upper() in ['1', 'ON', 'TRUE']:
            GPIO.output(pin, GPIO.HIGH)
            relay_states[relay_id] = True
            logger.info(f"Relais {relay_id} ACTIVÉ")
        elif payload.upper() in ['0', 'OFF', 'FALSE']:
            GPIO.output(pin, GPIO.LOW)
            relay_states[relay_id] = False
            logger.info(f"Relais {relay_id} DÉSACTIVÉ")
        else:
            logger.warning(f"Commande invalide pour le relais {relay_id}: {payload}")
            return
        
        # Publication de l'état actuel
        state_topic = MQTT_TOPIC_RELAY_STATE.format(relay_id)
        state_payload = "1" if relay_states[relay_id] else "0"
        client.publish(state_topic, state_payload, retain=True)
        
    except Exception as e:
        logger.error(f"Erreur commande relais {relay_id}: {e}")

def handle_led_command(client, payload):
    """Gestion des commandes pour la LED utilisateur"""
    global led_state
    try:
        if payload.upper() in ['1', 'ON', 'TRUE']:
            GPIO.output(LED_PIN, GPIO.HIGH)
            led_state = True
            logger.info("LED utilisateur ACTIVÉE")
        elif payload.upper() in ['0', 'OFF', 'FALSE']:
            GPIO.output(LED_PIN, GPIO.LOW)
            led_state = False
            logger.info("LED utilisateur DÉSACTIVÉE")
        
        # Publication de l'état actuel
        state_payload = "1" if led_state else "0"
        client.publish(MQTT_TOPIC_LED_STATE, state_payload, retain=True)
        
    except Exception as e:
        logger.error(f"Erreur commande LED: {e}")

def publish_initial_states(client):
    """Publication des états initiaux au démarrage"""
    for relay_id in RELAY_PINS.keys():
        state_topic = MQTT_TOPIC_RELAY_STATE.format(relay_id)
        state_payload = "1" if relay_states[relay_id] else "0"
        client.publish(state_topic, state_payload, retain=True)
    
    for input_id in INPUT_PINS.keys():
        state_topic = MQTT_TOPIC_INPUT_STATE.format(input_id)
        state_payload = "0" if input_states[input_id] else "1"  # Inversé car pull-up
        client.publish(state_topic, state_payload, retain=True)
    
    led_payload = "1" if led_state else "0"
    client.publish(MQTT_TOPIC_LED_STATE, led_payload, retain=True)
    
    logger.info("États initiaux publiés")

def monitor_inputs(client):
    """Surveillance continue des entrées digitales"""
    logger.info("Démarrage de la surveillance des entrées...")
    
    while True:
        try:
            for input_id, pin in INPUT_PINS.items():
                current_state = GPIO.input(pin)
                # Inverser l'état car nous utilisons pull-up
                inverted_state = not current_state
                
                if input_states[input_id] != current_state:
                    input_states[input_id] = current_state
                    
                    # Publication du nouvel état
                    state_topic = MQTT_TOPIC_INPUT_STATE.format(input_id)
                    state_payload = "1" if inverted_state else "0"
                    client.publish(state_topic, state_payload, retain=False)
                    
                    logger.info(f"Entrée {input_id} changée: {state_payload}")
            
            time.sleep(0.1)  # Pause de 100ms entre les vérifications
            
        except Exception as e:
            logger.error(f"Erreur surveillance entrées: {e}")
            time.sleep(1)

def main():
    """Fonction principale"""
    client = None  # Initialisation de client à None
    try:
        # Initialisation GPIO
        if not gpio_setup():
            logger.error("Échec de l'initialisation GPIO - Arrêt du programme")
            return
        
        # Configuration MQTT
        client = mqtt.Client()
        client.on_connect = on_connect
        client.on_message = on_message
        client.on_disconnect = on_disconnect
        
        # Configuration des identifiants MQTT
        client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
        
        # Configuration du Last Will Testament
        client.will_set(MQTT_TOPIC_STATUS, "offline", retain=True)
        
        # Connexion au broker
        logger.info(f"Connexion au broker MQTT {MQTT_BROKER}:{MQTT_PORT}")
        client.connect(MQTT_BROKER, MQTT_PORT, 60)
        
        # Démarrage de la surveillance des entrées dans un thread séparé
        input_thread = Thread(target=monitor_inputs, args=(client,), daemon=True)
        input_thread.start()
        
        # Boucle principale MQTT
        logger.info("Démarrage de la boucle MQTT...")
        client.loop_forever()
        
    except KeyboardInterrupt:
        logger.info("Arrêt demandé par l'utilisateur")
    except Exception as e:
        logger.error(f"Erreur critique: {e}")
    finally:
        # Nettoyage sécurisé
        if client:
            try:
                client.disconnect()
            except:
                pass
        try:
            GPIO.cleanup()
        except:
            pass
        logger.info("Nettoyage terminé, programme arrêté")

if __name__ == "__main__":
    main()

Rendre executable le script et donner les droits

chmod +x /home/nrx800/nrx-gpio.py
sudo usermod -a -G gpio nrx800

en SSH il faut installer les bibliothèques requises

sudo apt update
sudo apt install python3-venv
python3 -m venv ~/py_envs
source ~/py_envs/bin/activate
pip3 install paho-mqtt RPi.GPIO
python3 -m pip config set global.break-system-packages true

Si erreur

sudo apt install python3-pip
sudo apt install python3-paho-mqtt python3-rpi.gpio

En SHH pour une installation permanente, il faut créer un service systemd

sudo nano /etc/systemd/system/gpio-mqtt.service

Puis coller les lignes suivantes

gpio-mqtt.service
[Unit]
Description=GPIO MQTT Controller
After=network.target
Wants=mosquitto.service  # Si vous utilisez Mosquitto en local

[Service]
Type=simple
User=i%
WorkingDirectory=/home/nrx800
ExecStart=/usr/bin/python3 /home/nrx800/nrx-gpio.py
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1

[Install]
WantedBy=multi-user.target

puis activer et redémarrer

sudo systemctl enable gpio-mqtt.service
sudo systemctl start gpio-mqtt.service
sudo reboot

Après il faut retourner dans HA et créer une entité MQTT


Sachant qu’il faut 8 relais 8 entrées merci le nouveau HA !
Si vous voulez tester allez-y mais moi j’arrêtes là HA !

Honnêtement, vu la tournure que prends HA j’ai pas envie d’aller plus loin pour un truc qui fonctionnera peut-être plus dans 6 mois parce qu’il auront décide de verrouiller un peu plus !

Je me demande même comment vont s’installer et fonctionner les add-ons pour piloter les IPX800 v4 et v5 pour le coups si on peut plus installer HACS sur de nouvelles installs ?

Je pense que la meilleure approche est de soit installer le rpi-gpiod qui permet de piloter les gpio et de donner l’ip locale 127.0.0.1 ou la biblio gpiozero

par ex:

sudo apt update
sudo apt install pigpio
sudo systemctl enable pigpiod
sudo systemctl start pigpiod

puis un script python

from gpiozero import LED
from gpiozero.pins.pigpio import PiGPIOFactory
from time import sleep

# Utilise localhost ou 127.0.0.1 pour le contrôle local
factory = PiGPIOFactory(host='localhost')  # ou host='127.0.0.1'

led = LED(17, pin_factory=factory)

while True:
    led.on()
    sleep(1)
    led.off()
    sleep(1)

mais la question est avec quelle solution domotique ensuite ?

Je dirais la 1ere approche est le script python pour piloter les IO via MQTT puis une solution comme Gladys assistant qui permet de lier des commandes mqtt à des appareils virtuels

Allez c’est malin maintenant je suis tenté de l’installer sur le NRX pour voir ce que cela donnes avec les GPIO et la cle zigbee (quasi sure pour elle que pas de prob) !!! :joy:
(Je l’ai sur un nuc bt3 pro 4go c’est pas trop gourmand !)

Bonjour @cce66,

Effectivement tu t’es donné :smiley: Je suis autant déçu que toi sur HA, le fait de verrouiller autant pour une solution qui se disait opensource, je trouve ça dommage… Merci en tout cas, tous ces tests m’ont permis de voir que HA n’est pas le plus pratique sur NRX.

Je ne connais pas du tout Gladys mais ça à l’air compatible Zigbee et d’autres protocoles. Je vais aller me renseigner sur le sujet.

Merci encore pour ton aide ! :slight_smile: Et si jamais tu te fais une tentative sur Gladys, je veux bien voir se que cela donne. Je tenterais peut-être de mon côté si la solution m’attire.

Bonne continuation !

Ca me gêne de lire que HA est verrouillé, c’est de loin la solution de domotique la plus ouverte :winking_face_with_tongue:

Et ils font l’effort de supporter pas mal de hardware différents en fabricant une véritable distribution linux adaptée, qui garantit perf et sécurité.

Le problème ici, c’est qu’on est pas sur un hardware standard. Le NRX800 est plus proche du hardware yellow box que d’un RPI classique.

Vous avez essayé d’utiliser les images pour yellow box ?

Le NRX800 ferait un super produit pour HAOS, j’avais évoqué ça dans un autre threaad avec @GCE , je reste persuadé que ça vaudrait le cout d’avoir un échange avec la Open Home Foundation pour voir si le NRX pourrait être supporté.

Il y a plusieurs français chez Home Assistant, comme JLo à qui ça pourrait être intéressant d’en parler.

Bonjour @mcc37

Nuance, j’ai dit se verrouille par rapport à ce qu’il était avant, ouverte oui mais sur du standard uniquement, je suis étonné pour HACS…Après je suis pas un spécialiste de HA je m’en sers qu’occasionnellement…

Non, mais comme mentionné le problème est lié au fait qu’avec HAOS on ne peut pas ajouter de pilotes ici les gpio, l’usb et certainement le rtc (mais j’ai pas testé le yellow box il faudrait qu’il y ai le même hardware pour que cela fonctionnes ) et qu’en container il y a pas/plus d’add-ons possibles…

Clairement, mais je suis pas certain qu’ils seraient intéressés de faire un dev d’image pour le NRX…En tout cas maintenant les problèmes rencontrés sont référencés :slightly_smiling_face:

Je laisse ce soin à qui voudrait gérer cela ou à @GCE car je suis sur un autre projet actuellement et j’ai pas le temps pour le moment.