FEAT : Anémotrètre en modbus -> mqtt OK :-)
This commit is contained in:
commit
4ca0462d58
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
venv/
|
||||
14
compose.yml
Normal file
14
compose.yml
Normal file
@ -0,0 +1,14 @@
|
||||
version: '3'
|
||||
services:
|
||||
esphome:
|
||||
container_name: esphome
|
||||
image: ghcr.io/esphome/esphome:2025.4.2
|
||||
volumes:
|
||||
- "${PWD}/config:/config"
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
restart: always
|
||||
privileged: true
|
||||
network_mode: host
|
||||
environment:
|
||||
- USERNAME=admin
|
||||
- PASSWORD=admin
|
||||
5
config/.gitignore
vendored
Normal file
5
config/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Gitignore settings for ESPHome
|
||||
# This is an example and may include too much for your use-case.
|
||||
# You can modify this file to suit your needs.
|
||||
/.esphome/
|
||||
/secrets.yaml
|
||||
48
config/archive/seed-modbus.yaml
Normal file
48
config/archive/seed-modbus.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
esphome:
|
||||
name: seed-modbus
|
||||
friendly_name: seed modbus
|
||||
|
||||
esp32:
|
||||
board: esp32-s3-devkitc-1
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: "+fvyzEhRt2I4BPtrS9dqhv/qCibX0azYMgMY1tkEOLw="
|
||||
|
||||
ota:
|
||||
- platform: esphome
|
||||
password: "c3274286d9131444822bed49abf1b77b"
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: "Seed-Modbus Fallback Hotspot"
|
||||
password: "j9tvzwj9WPEe"
|
||||
|
||||
captive_portal:
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
pin: GPIO21 #GPIO4
|
||||
id: led_output
|
||||
|
||||
switch:
|
||||
- platform: output
|
||||
name: "LED"
|
||||
output: led_output
|
||||
id: led_switch
|
||||
restore_mode: ALWAYS_OFF
|
||||
|
||||
interval:
|
||||
- interval: 1s
|
||||
then:
|
||||
- switch.toggle: led_switch
|
||||
117
config/seed-modbus.yaml.save
Normal file
117
config/seed-modbus.yaml.save
Normal file
@ -0,0 +1,117 @@
|
||||
esphome:
|
||||
name: seed-modbus
|
||||
friendly_name: seed modbus
|
||||
on_boot:
|
||||
then:
|
||||
- output.turn_on: output1
|
||||
|
||||
esp32:
|
||||
board: esp32-s3-devkitc-1
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: "6wSuBPbrOHBZNl2RG7Dha1yjHddwhVbNK82ET4Pcz3I="
|
||||
|
||||
ota:
|
||||
- platform: esphome
|
||||
password: "6ce9a2a585eb85f9a150d88e6c676483"
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
uart:
|
||||
id: uart_bus_a
|
||||
# TX/RX carte :
|
||||
rx_pin: GPIO44
|
||||
tx_pin: GPIO43
|
||||
# RX=D4 -> GPIO5, TX=D5 -> GPIO6
|
||||
# rx_pin: GPIO5
|
||||
# tx_pin: GPIO6
|
||||
# RX=D7, TX=D6
|
||||
baud_rate: 4800
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
id: output1
|
||||
pin:
|
||||
number: GPIO3
|
||||
mode:
|
||||
output: True
|
||||
|
||||
modbus:
|
||||
id: modbus1
|
||||
uart_id: uart_bus_a
|
||||
|
||||
modbus_controller:
|
||||
- id: modbus_controller1
|
||||
address: 1
|
||||
modbus_id: modbus1
|
||||
update_interval: 2s
|
||||
|
||||
# select:
|
||||
# - platform: modbus_controller
|
||||
# name: "Modbus Select Register 0"
|
||||
# address: 1
|
||||
# value_type: U_WORD
|
||||
# optionsmap:
|
||||
# "Zero": 0
|
||||
# "One": 1
|
||||
# "Two": 2
|
||||
# "Three": 3
|
||||
|
||||
|
||||
# select:
|
||||
# - platform: modbus_controller
|
||||
# name: "Modbus Select Register 1"
|
||||
# address: 1
|
||||
# value_type: U_WORD
|
||||
# optionsmap:
|
||||
# "Zero": 0
|
||||
# "One": 1
|
||||
# "Two": 2
|
||||
# "Three": 3
|
||||
# lambda: |-
|
||||
# ESP_LOGD("Reg1000", "Received value %lld", x);
|
||||
|
||||
mqtt:
|
||||
broker: "pc-raymond-wifi.home"
|
||||
id: mqtt1
|
||||
log_topic: rbo
|
||||
|
||||
sensor:
|
||||
- platform: modbus_controller
|
||||
id: sensor1
|
||||
modbus_controller_id: modbus_controller1
|
||||
name: "Wind speed"
|
||||
device_class: wind_speed
|
||||
register_type: holding
|
||||
address: 0
|
||||
unit_of_measurement: "m/s"
|
||||
value_type: U_WORD
|
||||
accuracy_decimals: 1
|
||||
filters:
|
||||
- multiply: 0.1
|
||||
- max:
|
||||
window_size: 5
|
||||
send_every: 5
|
||||
- exponential_moving_average:
|
||||
alpha: 0.1
|
||||
send_every: 12
|
||||
- platform: template
|
||||
id: mqtt_wind_speed
|
||||
lambda: |-
|
||||
ESP_LOGD("Reg1000", "Received value %lld", id(sensor1).state);
|
||||
return id(sensor1).state;
|
||||
on_value:
|
||||
then:
|
||||
- mqtt.publish:
|
||||
topic: "home/wind_speed"
|
||||
payload: !lambda 'return to_string(id(mqtt_wind_speed).state);'
|
||||
116
config/seeed-studio.yaml
Normal file
116
config/seeed-studio.yaml
Normal file
@ -0,0 +1,116 @@
|
||||
esphome:
|
||||
name: seeed-studio
|
||||
friendly_name: seeed studio
|
||||
on_boot:
|
||||
then:
|
||||
- output.turn_on: DE_RE
|
||||
|
||||
esp32:
|
||||
board: esp32-s3-devkitc-1
|
||||
framework:
|
||||
type: arduino
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
|
||||
# Enable Home Assistant API
|
||||
api:
|
||||
encryption:
|
||||
key: "1tRYVfsGzt8mFr+ay9hE24pdPd8IACedduh9tLWg4xs="
|
||||
|
||||
ota:
|
||||
- platform: esphome
|
||||
password: "d68060a1d18b9d61354434595717070c"
|
||||
|
||||
wifi:
|
||||
ssid: !secret wifi_ssid
|
||||
password: !secret wifi_password
|
||||
|
||||
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
||||
ap:
|
||||
ssid: "Seeed-Studio Fallback Hotspot"
|
||||
password: "FrTglhXBIVqi"
|
||||
|
||||
captive_portal:
|
||||
|
||||
output:
|
||||
- platform: gpio
|
||||
pin: GPIO21 # Led de la carte
|
||||
id: led_output
|
||||
- platform: gpio
|
||||
pin: GPIO3 # le pin connecté à DE/RE
|
||||
id: DE_RE
|
||||
|
||||
switch:
|
||||
- platform: output
|
||||
name: "LED"
|
||||
output: led_output
|
||||
id: led_switch
|
||||
restore_mode: ALWAYS_OFF
|
||||
|
||||
interval:
|
||||
- interval: 5s
|
||||
then:
|
||||
- switch.toggle: led_switch
|
||||
- logger.log: "rbo2"
|
||||
|
||||
uart:
|
||||
id: mod_bus_id
|
||||
tx_pin: GPIO44 # Il faut les inverser !!!!
|
||||
rx_pin: GPIO43
|
||||
baud_rate: 4800
|
||||
debug:
|
||||
direction: BOTH
|
||||
dummy_receiver: false
|
||||
after:
|
||||
delimiter: "\n"
|
||||
sequence:
|
||||
- lambda: UARTDebug::log_string(direction, bytes);
|
||||
|
||||
modbus:
|
||||
id: modbus1
|
||||
uart_id: mod_bus_id
|
||||
|
||||
modbus_controller:
|
||||
- id: modbus_controller1
|
||||
address: 1
|
||||
modbus_id: modbus1
|
||||
setup_priority: -10
|
||||
command_throttle: 2s
|
||||
update_interval: 4s
|
||||
|
||||
sensor:
|
||||
- platform: modbus_controller
|
||||
id: sensor1
|
||||
modbus_controller_id: modbus_controller1
|
||||
name: "Wind speed"
|
||||
device_class: wind_speed
|
||||
register_type: holding
|
||||
address: 0
|
||||
unit_of_measurement: "m/s"
|
||||
value_type: U_WORD
|
||||
accuracy_decimals: 1
|
||||
filters:
|
||||
- multiply: 0.1
|
||||
- max:
|
||||
window_size: 1
|
||||
send_every: 1
|
||||
- min:
|
||||
window_size: 1
|
||||
send_every: 1
|
||||
# - exponential_moving_average:
|
||||
# alpha: 0.1
|
||||
# send_every: 12
|
||||
on_value:
|
||||
then:
|
||||
- mqtt.publish:
|
||||
topic: "rbo2"
|
||||
payload: !lambda 'return to_string(x);'
|
||||
|
||||
mqtt:
|
||||
broker: "pc-raymond.home"
|
||||
id: mqtt1
|
||||
log_topic: rbo
|
||||
birth_message:
|
||||
topic: rbo2
|
||||
payload: 'send_every: 1 !'
|
||||
9
mqtt/compose.yml
Normal file
9
mqtt/compose.yml
Normal file
@ -0,0 +1,9 @@
|
||||
services:
|
||||
mqtt:
|
||||
image: eclipse-mosquitto:2.0
|
||||
restart: unless-stopped
|
||||
# volumes:
|
||||
# - /grab/data/mosquitto:/mosquitto
|
||||
ports:
|
||||
- 1883:1883
|
||||
command: "mosquitto -c /mosquitto-no-auth.conf"
|
||||
20
notes.md
Normal file
20
notes.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Notes
|
||||
|
||||
## Matériel
|
||||
|
||||
### Anémomètre
|
||||
|
||||
SN-3000-FSJT-N01
|
||||
|
||||
```
|
||||
Nom : Lecteur de pare-brise en polycarbonate 485
|
||||
Alimentation : 10~30V
|
||||
Séquence de lignes :
|
||||
Marron : alimentation positive
|
||||
Noir : alimentation négative
|
||||
Jaune (vert) : 485 A
|
||||
Bleu : 485 B
|
||||
Numéro de lot : 2502
|
||||
Propriétaire : Shandong Saien Electronic Technology Co., Ltd.
|
||||
Adresse : n° 1193, route Gangyuan, ville de Jinan, province du Shandong
|
||||
```
|
||||
58
proto/configModel.py
Normal file
58
proto/configModel.py
Normal file
@ -0,0 +1,58 @@
|
||||
from typing import Optional
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
|
||||
class Algo(Enum):
|
||||
IEEE2 = "ieee754_sur_2_registres"
|
||||
NORMAL = "lecture_directe"
|
||||
STRING = "Chaîne de caractères"
|
||||
UINT32 = "Entier sur 32 bits non signé"
|
||||
BOOLEAN = "Booléen"
|
||||
|
||||
@dataclass
|
||||
class Metrique:
|
||||
# Id de la métrique pour ce capteur :
|
||||
idMetrique:int
|
||||
indexRegistreDepart:int
|
||||
indexRegistreFin:int = None # Ne sert que dans le cas de Algo.STRING
|
||||
# Nombre de chiffres après la virgule (utilisé si Algo.IEEE2)
|
||||
precision:int = 2
|
||||
algo:Algo = Algo.NORMAL
|
||||
|
||||
class ModbusType(Enum):
|
||||
RTU = "rtu"
|
||||
TCP = "tcp"
|
||||
|
||||
@dataclass
|
||||
class RtuConfig:
|
||||
baudrate:int
|
||||
stopbits:int
|
||||
bytesize:int
|
||||
parity:str
|
||||
serialPort:str = "/dev/ttyACM0"
|
||||
|
||||
@dataclass
|
||||
class TcpConfig:
|
||||
ip:str
|
||||
|
||||
@dataclass
|
||||
class AppelCapteur:
|
||||
firstRegisterAdress:int
|
||||
nbRegisters:int
|
||||
# Les métriques associées à ce capteur
|
||||
metriques:list[Metrique]
|
||||
# Le délais, en secondes, entre 2 appels (et stockage en bdd des métriques liées) avec 15s comme valeur par défaut :
|
||||
delai:int = 15
|
||||
|
||||
@dataclass
|
||||
class Capteur:
|
||||
idCapteur:int
|
||||
modbusAdresse:int
|
||||
appels:list[AppelCapteur]
|
||||
|
||||
@dataclass
|
||||
class Canal:
|
||||
description:str
|
||||
typeModbus:ModbusType
|
||||
comConfig:RtuConfig|TcpConfig
|
||||
capteurs:list[Capteur]
|
||||
7
proto/requirements.txt
Normal file
7
proto/requirements.txt
Normal file
@ -0,0 +1,7 @@
|
||||
APScheduler==3.10.4
|
||||
psycopg2-binary==2.9.10
|
||||
pymodbus==3.7.0
|
||||
pyserial==3.5
|
||||
pytz==2024.1
|
||||
six==1.16.0
|
||||
tzlocal==5.2
|
||||
60
proto/t.py
Executable file
60
proto/t.py
Executable file
@ -0,0 +1,60 @@
|
||||
#!python
|
||||
from pymodbus.client import ModbusSerialClient, ModbusTcpClient
|
||||
from pymodbus.pdu.register_read_message import ReadInputRegistersResponse
|
||||
from configModel import Algo, Metrique, Capteur, ModbusType
|
||||
import struct, time
|
||||
|
||||
# client = ModbusTcpClient(host="shellyproem50-08f9e0e79718") # grarage (borne et pac)
|
||||
# client = ModbusTcpClient(host="ShellyPro3EM-FCE8C0D97664") # bureau (prises 1 à 3)
|
||||
client = ModbusSerialClient(
|
||||
port="/dev/ttyACM0",
|
||||
baudrate=4800,
|
||||
# stopbits=capteur.comConfig.stopbits,
|
||||
# bytesize=capteur.comConfig.bytesize,
|
||||
# parity=capteur.comConfig.parity
|
||||
)
|
||||
|
||||
def ieee754(registres:list):
|
||||
float_bytes = struct.pack('HH', registres[0], registres[1])
|
||||
return struct.unpack('f', float_bytes)[0]
|
||||
|
||||
def uint32(a, b):
|
||||
ret:int = (a << 16) | b
|
||||
return ret
|
||||
|
||||
def lireMetrique(metrique:Metrique, registre):
|
||||
client.connect()
|
||||
try:
|
||||
data:ReadInputRegistersResponse = client.read_input_registers(registre, 2, slave=1)
|
||||
if data:
|
||||
print(f"--> {data}")
|
||||
registres = data.registers
|
||||
if metrique.algo == Algo.NORMAL:
|
||||
val = registres[0]
|
||||
if metrique.algo == Algo.IEEE2:
|
||||
val = round(ieee754(registres[0:2]), metrique.precision)
|
||||
if metrique.algo == Algo.UINT32:
|
||||
val = uint32(registres[0], registres[1])
|
||||
if metrique.algo == Algo.STRING:
|
||||
val = ''.join(chr(register) for register in data.registers)
|
||||
if metrique.algo == Algo.BOOLEAN:
|
||||
val = registres[0]
|
||||
print(f"Captation sur {registre} : {val}")
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la captation sur {registre} : {e}")
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
registre = -1
|
||||
|
||||
if __name__ == '__main__':
|
||||
while True:
|
||||
registre = 0
|
||||
m:Metrique = Metrique(
|
||||
idMetrique=1,
|
||||
indexRegistreDepart=registre,
|
||||
precision=3,
|
||||
algo=Algo.NORMAL
|
||||
)
|
||||
lireMetrique(m, registre)
|
||||
time.sleep(1)
|
||||
Loading…
Reference in New Issue
Block a user