Se rendre au contenu

← Connexion matérielle | Sommaire | Suivant : Communication I2C →

Communication UART

Description détaillée du protocole UART pour le pilotage de DimmerLink.




Paramètres de connexion

Paramètre Valeur
Débit (Baud Rate) 115200
Bits de données 8
Parité Aucune (N)
Bits de stop 1
Format 8N1

ℹ️ Remarque : L'interface UART est disponible dès la mise sous tension.




Format des commandes

Toutes les commandes commencent par l'octet de démarrage 0x02 (STX — Start of Text) :

python
┌──────────┬──────────┬──────────┬──────────┐
│  START   │   CMD    │   ARG1   │   ARG2   │
│   0x02   │  1 byte  │ optional │ optional │
└──────────┴──────────┴──────────┴──────────┘

⚠️ Important : Sans l'octet de démarrage 0x02, la commande ne sera pas traitée !




Table des commandes

Commande Code Format Description
SET 0x53 ('S') 02 53 IDX LEVEL Définir la luminosité
GET 0x47 ('G') 02 47 IDX Obtenir la luminosité
CURVE 0x43 ('C') 02 43 IDX TYPE Définir la courbe de variation
GETCURVE 0x51 ('Q') 02 51 IDX Obtenir le type de courbe
FREQ 0x52 ('R') 02 52 Obtenir la fréquence du réseau
RESET 0x58 ('X') 02 58 Réinitialisation logicielle
SWITCH_I2C 0x5B ('[') 02 5B Basculer vers I2C


Paramètres

  • IDX — index du variateur (0–7, la version actuelle ne prend en charge que 0. Les valeurs 1–7 sont réservées pour les futures versions multicanaux)
  • LEVEL — luminosité 0–100 (pourcentage)
  • TYPE — type de courbe : 0=LINEAR, 1=RMS, 2=LOG



Codes de réponse

Code Nom Description
0x00 OK Commande exécutée avec succès
0xF9 ERR_SYNTAX Format invalide ou commande inconnue
0xFC ERR_NOT_READY Erreur d'écriture EEPROM
0xFD ERR_INDEX Index de variateur invalide
0xFE ERR_PARAM Valeur de paramètre invalide



Description des commandes


SET — Définir la luminosité

Format : 02 53 IDX LEVEL

python
Example: 02 53 00 32  → Set dimmer 0 to 50%
Response: 00          → OK
LEVEL Luminosité
0x00 (0) 0% — éteint
0x32 (50) 50%
0x64 (100) 100% — pleine luminosité


GET — Obtenir la luminosité actuelle

Format : 02 47 IDX

python
Example: 02 47 00     → Request dimmer 0 brightness
Response: 00 32       → OK, level 50%

📝 Remarque : GET renvoie la valeur en pourcentage (0–100), tout comme SET.


CURVE — Définir la courbe de variation

Format : 02 43 IDX TYPE

TYPE Courbe Application
0 LINEAR Universelle
1 RMS Incandescent, halogène
2 LOG LED (correspond à la perception visuelle)
python
Example: 02 43 00 01  → Set RMS curve for dimmer 0
Response: 00          → OK


GETCURVE — Obtenir le type de courbe

Format : 02 51 IDX

python
Example: 02 51 00     → Request dimmer 0 curve type
Response: 00 00       → OK, type LINEAR


FREQ — Obtenir la fréquence du réseau

Format : 02 52

python
Example: 02 52        → Request frequency
Response: 00 32       → OK, 50 Hz (0x32 = 50)
Or:      00 3C       → OK, 60 Hz (0x3C = 60)


RESET — Réinitialisation logicielle

Format : 02 58

python
Example: 02 58        → Reset device
(no response — device reboots)


SWITCH_I2C — Basculer vers I2C

Format : 02 5B

python
Example: 02 5B        → Switch interface to I2C
Response: 00          → OK (last UART response)

Après exécution réussie, le UART est désactivé et l'appareil passe en mode I2C. Le contrôle se fait ensuite uniquement via I2C à l'adresse 0x50 (ou l'adresse configurée).

📝 Remarque : Le mode est sauvegardé dans l'EEPROM et restauré après redémarrage.




Exemples de code


Arduino

cpp
// Use Serial1 for boards with multiple UARTs (Mega, Due, ESP32)
// Or SoftwareSerial for Uno/Nano

// For Arduino Mega, Due, ESP32 — use Serial1, Serial2
// For Arduino Uno/Nano — use SoftwareSerial (see example below)
#define DIMMER_SERIAL Serial1

void setup() {
    DIMMER_SERIAL.begin(115200);
}

// Set brightness (0-100%)
bool setLevel(uint8_t level) {
    uint8_t cmd[] = {0x02, 0x53, 0x00, level};
    DIMMER_SERIAL.write(cmd, 4);

    delay(10);
    if (DIMMER_SERIAL.available()) {
        return DIMMER_SERIAL.read() == 0x00;
    }
    return false;
}

// Get current brightness (returns 0-100%)
int getLevel() {
    uint8_t cmd[] = {0x02, 0x47, 0x00};
    DIMMER_SERIAL.write(cmd, 3);

    delay(10);
    if (DIMMER_SERIAL.available() >= 2) {
        uint8_t status = DIMMER_SERIAL.read();
        uint8_t level = DIMMER_SERIAL.read();
        if (status == 0x00) {
            return level;
        }
    }
    return -1;
}

// Set curve (0=LINEAR, 1=RMS, 2=LOG)
bool setCurve(uint8_t curve) {
    uint8_t cmd[] = {0x02, 0x43, 0x00, curve};
    DIMMER_SERIAL.write(cmd, 4);

    delay(10);
    if (DIMMER_SERIAL.available()) {
        return DIMMER_SERIAL.read() == 0x00;
    }
    return false;
}

// Get mains frequency (50 or 60 Hz)
int getFrequency() {
    uint8_t cmd[] = {0x02, 0x52};
    DIMMER_SERIAL.write(cmd, 2);

    delay(10);
    if (DIMMER_SERIAL.available() >= 2) {
        uint8_t status = DIMMER_SERIAL.read();
        uint8_t freq = DIMMER_SERIAL.read();
        if (status == 0x00) {
            return freq;
        }
    }
    return -1;
}

void loop() {
    setLevel(50);   // 50%
    delay(2000);
    setLevel(100);  // 100%
    delay(2000);
}


Arduino avec SoftwareSerial (pour Uno/Nano)

cpp
#include 

SoftwareSerial dimmerSerial(10, 11);  // RX, TX

void setup() {
    Serial.begin(115200);
    dimmerSerial.begin(115200);

    Serial.println("DimmerLink ready");
}

bool setLevel(uint8_t level) {
    uint8_t cmd[] = {0x02, 0x53, 0x00, level};
    dimmerSerial.write(cmd, 4);

    delay(10);
    if (dimmerSerial.available()) {
        return dimmerSerial.read() == 0x00;
    }
    return false;
}

void loop() {
    if (setLevel(50)) {
        Serial.println("Set to 50%: OK");
    } else {
        Serial.println("Set to 50%: ERROR");
    }
    delay(3000);
}

⚠️ Remarque : SoftwareSerial sur Arduino Uno/Nano peut être instable à 115200 bauds. En cas d'erreurs de communication, nous recommandons d'utiliser l'interface I2C ou une carte avec UART matériel (Arduino Mega, ESP32).


Python (pyserial)

python
import serial
import time

class DimmerLink:
    def __init__(self, port, baudrate=115200):
        try:
            self.ser = serial.Serial(port, baudrate, timeout=0.1)
        except serial.SerialException as e:
            print(f"Connection error to {port}: {e}")
            print("Check:")
            print("  - Is USB-UART adapter connected?")
            print("  - Correct port? (Windows: COM3, Linux: /dev/ttyUSB0)")
            raise

    def set_level(self, level):
        """Set brightness 0-100%"""
        cmd = bytes([0x02, 0x53, 0x00, level])
        self.ser.write(cmd)
        resp = self.ser.read(1)
        return len(resp) > 0 and resp[0] == 0x00

    def get_level(self):
        """Get brightness 0-100%"""
        cmd = bytes([0x02, 0x47, 0x00])
        self.ser.write(cmd)
        resp = self.ser.read(2)
        if len(resp) == 2 and resp[0] == 0x00:
            return resp[1]
        return None

    def set_curve(self, curve_type):
        """Set curve: 0=LINEAR, 1=RMS, 2=LOG"""
        cmd = bytes([0x02, 0x43, 0x00, curve_type])
        self.ser.write(cmd)
        resp = self.ser.read(1)
        return len(resp) > 0 and resp[0] == 0x00

    def get_frequency(self):
        """Get mains frequency (50 or 60 Hz)"""
        cmd = bytes([0x02, 0x52])
        self.ser.write(cmd)
        resp = self.ser.read(2)
        if len(resp) == 2 and resp[0] == 0x00:
            return resp[1]
        return None

    def close(self):
        self.ser.close()

# Usage example
if __name__ == "__main__":
    # Windows: 'COM3', Linux: '/dev/ttyUSB0'
    dimmer = DimmerLink('/dev/ttyUSB0')

    print(f"Mains frequency: {dimmer.get_frequency()} Hz")

    # Smooth brightness change
    for level in range(0, 101, 10):
        if dimmer.set_level(level):
            print(f"Brightness: {level}%")
        time.sleep(0.5)

    dimmer.close()


MicroPython (ESP32, Raspberry Pi Pico)

python
from machine import UART, Pin
import time

class DimmerLink:
    def __init__(self, uart_id=1, tx_pin=17, rx_pin=16):
        self.uart = UART(uart_id, baudrate=115200, tx=Pin(tx_pin), rx=Pin(rx_pin))

    def set_level(self, level):
        """Set brightness 0-100%"""
        cmd = bytes([0x02, 0x53, 0x00, level])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any():
            return self.uart.read(1)[0] == 0x00
        return False

    def get_level(self):
        """Get brightness 0-100%"""
        cmd = bytes([0x02, 0x47, 0x00])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any() >= 2:
            resp = self.uart.read(2)
            if resp[0] == 0x00:
                return resp[1]
        return None

    def set_curve(self, curve_type):
        """Set curve: 0=LINEAR, 1=RMS, 2=LOG"""
        cmd = bytes([0x02, 0x43, 0x00, curve_type])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any():
            return self.uart.read(1)[0] == 0x00
        return False

    def get_frequency(self):
        """Get mains frequency"""
        cmd = bytes([0x02, 0x52])
        self.uart.write(cmd)
        time.sleep_ms(10)
        if self.uart.any() >= 2:
            resp = self.uart.read(2)
            if resp[0] == 0x00:
                return resp[1]
        return None

# Usage example
dimmer = DimmerLink()

print(f"Mains frequency: {dimmer.get_frequency()} Hz")

while True:
    for level in range(0, 101, 10):
        dimmer.set_level(level)
        print(f"Brightness: {level}%")
        time.sleep(0.5)



Pour ceux qui ne connaissent pas le HEX

HEX (hexadécimal) est une façon d'écrire les nombres.

Décimal HEX Remarque
0 0x00 Zéro
50 0x32 Cinquante
100 0x64 Cent
255 0xFF Maximum pour 1 octet


Comment convertir un nombre en HEX

Python :

python
level = 50
hex_value = hex(level)  # '0x32'
print(f"50 in HEX = {hex_value}")

Arduino :

cpp
int level = 50;
Serial.print("50 in HEX = 0x");
Serial.println(level, HEX);  // Prints "32"


Aide-mémoire : luminosité en HEX

Luminosité HEX Commande SET
0% (éteint) 0x00 02 53 00 00
10% 0x0A 02 53 00 0A
25% 0x19 02 53 00 19
50% 0x32 02 53 00 32
75% 0x4B 02 53 00 4B
100% 0x64 02 53 00 64


Fonction utilitaire pour construire les commandes

Python :

python
def make_set_command(level_percent):
    """Create SET command from percent"""
    return bytes([0x02, 0x53, 0x00, level_percent])

# Usage
cmd = make_set_command(75)  # 75%
print(f"Command: {cmd.hex()}")  # Prints: 0253004b

Arduino :

cpp
void sendSetCommand(uint8_t level) {
    uint8_t cmd[] = {0x02, 0x53, 0x00, level};
    Serial1.write(cmd, 4);
}

// Usage
sendSetCommand(75);  // 75%



Débogage


Test de connexion

Envoyez la commande de demande de fréquence :

python
TX: 02 52
RX: 00 32  (OK, 50 Hz)


Erreurs courantes

Problème Cause Solution
Pas de réponse Octet START manquant Ajouter 0x02 au début
Pas de réponse Mauvais débit Vérifier 115200
Pas de réponse Interface en mode I2C Rebasculer vers UART
0xF9 Commande inconnue Vérifier le code de commande
0xFC Erreur d'écriture EEPROM Réessayer la commande
0xFE Paramètre invalide level > 100 ou curve > 2


Programmes de terminal

For debugging you can use:
- Windows: RealTerm (HEX mode), SSCOM
- Linux: picocom, minicom
- Cross-platform: PuTTY, CoolTerm




What's Next?

← Connexion matérielle | Sommaire | Suivant : Communication I2C →