« Home Assistant » : différence entre les versions
| (6 versions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 426 : | Ligne 426 : | ||
# grep filter mqtt-hassio.cfg | grep "=" | grep -v "^#" | # grep filter mqtt-hassio.cfg | grep "=" | grep -v "^#" | ||
filter-seen = 5 | filter-seen = 5 | ||
filter-name = status|temp|humidity|yield|count|energy|power|runtime|hours|starts|mode|curve|^load$|^party$|sensor|timer| | filter-name = status|temp|humidity|yield|count|energy|power|runtime|hours|starts|mode|curve|^load$|^party$|sensor|timer|Water | ||
filter-non-name = | filter-non-name = TempBottom|TempTop|SystemFlowTemp|^Status$|WaterHcFlowMax|ValveStarts|SHEMaxFlowTemp|PredSourcePressurePredCounter|PredWaterflowDevThreshold|PredWaterflowSwitchingP | ||
filter-level = ^$ | filter-level = ^$ | ||
filter-direction = r|u | filter-direction = r|u | ||
| Ligne 434 : | Ligne 434 : | ||
</pre> | </pre> | ||
When the application starts, it will fetch latest csv's & inc file from https://ebus.github.io/de/. | |||
<pre> | That's not ideal, let's depend only on local content: | ||
On your favorite endpoint: | |||
<pre> | |||
wget https://ebus.github.io/en/broadcast.csv | |||
wget https://ebus.github.io/en/memory.csv | |||
mkdir -p vaillant | |||
cd vaillant | |||
2026- | wget https://ebus.github.io/en/vaillant/broadcast.csv | ||
2026-03- | wget https://ebus.github.io/en/vaillant/general.csv | ||
wget https://ebus.github.io/en/vaillant/scan.csv | |||
wget https://ebus.github.io/en/vaillant/08.bai.csv | |||
wget https://ebus.github.io/en/vaillant/15.700.csv | |||
wget https://ebus.github.io/en/vaillant/bai.0010006101.inc | |||
</pre> | |||
Add important missing VRC700 Humidity metric: | |||
<pre>% diff -u 15.700.csv.20260328 15.700.csv | |||
--- 15.700.csv.20260328 2026-02-01 17:09:58.000000000 +0100 | |||
+++ 15.700.csv 2026-03-28 21:29:44.000000000 +0100 | |||
@@ -33,6 +33,7 @@ | |||
w,,,Time,time,,,b524,020100003500,value,,HTI,,,Aktuelle Uhrzeit | |||
r,,,HydraulicScheme,Systemschema,,,b524,020000003600,ign,,IGN:4,,,,value,,UIN,,,Systemschema | |||
w,,,HydraulicScheme,Systemschema,,,b524,020100003600,value,,UIN,,,Systemschema | |||
+r,,,RoomHumidity,room humidity,,,b524,060009010700,ign,,IGN:4,,,,humidity,,EXP,,%,room humidity | |||
r,,,WaterPressure,water pressure,,,b524,020000003900,ign,,IGN:4,,,,value,,EXP,,bar,Wasserdruck | |||
r,,,SolarYieldTotal,total solar yield,,,b524,020000003d00,ign,,IGN:4,,,,value,,ULG,,kWh,Solarertrag gesamt | |||
w,,,SolarYieldTotal,total solar yield,,,b524,020100003d00,value,,ULG,,kWh,Solarertrag gesamt</pre> | |||
[ | Upload the definitions in the right container config directory: | ||
<pre>scp -P 22222 *.csv root@192.168.1.111:/mnt/data/supervisor/addon_configs/b4d7ad18_ebusd/custom/vaillant/ | |||
scp -P 22222 *.inc root@192.168.1.111:/mnt/data/supervisor/addon_configs/b4d7ad18_ebusd/custom/vaillant/ | |||
cd .. | |||
scp -P 22222 *.csv root@192.168.1.111:/mnt/data/supervisor/addon_configs/b4d7ad18_ebusd/custom/</pre> | |||
Configure eBUSd to use this configpath: | |||
<pre>commandline_options: | |||
- "--mqttjson" | |||
- "--scanconfig" | |||
- "--log=all:error" | |||
- "--enabledefine" | |||
- "--configpath=/config/custom/" | |||
network_device: ens:/dev/ttyACM0</pre> | |||
TBC, copy the live container content to the general config: | |||
<pre>[core-ssh ebusd-configuration]$ cp -rpf /addon_configs/b4d7ad18_ebusd/* . | |||
[core-ssh ebusd-configuration]$ pwd | |||
/homeassistant/ebusd-configuration | |||
[core-ssh ebusd-configuration]$ cp -rpf /addon_configs/b4d7ad18_ebusd/* . | |||
[core-ssh ebusd-configuration]$ find . | |||
. | |||
./custom | |||
./custom/vaillant | |||
./custom/vaillant/bai.0010006101.inc | |||
./custom/vaillant/08.bai.csv | |||
./custom/vaillant/broadcast.csv | |||
./custom/vaillant/15.700.csv | |||
./custom/vaillant/scan.csv | |||
./custom/vaillant/general.csv | |||
./custom/memory.csv | |||
./custom/broadcast.csv | |||
./mqtt-hassio.cfg.2026032701 | |||
./mqtt-hassio.cfg | |||
[core-ssh ebusd-configuration]$ </pre> | |||
=== MQTT === | === MQTT === | ||
| Ligne 492 : | Ligne 521 : | ||
} | } | ||
}</pre> | }</pre> | ||
Note that this entity should be created automatically when it will be published on the bus. | |||
=== WebUI === | === WebUI === | ||
| Ligne 499 : | Ligne 530 : | ||
device: /dev/ttyACM0, serial high speed, enhanced, firmware 1.1[6112].1[6112] | device: /dev/ttyACM0, serial high speed, enhanced, firmware 1.1[6112].1[6112] | ||
signal: acquired | signal: acquired | ||
symbol rate: | symbol rate: 44 | ||
max symbol rate: | max symbol rate: 127 | ||
min arbitration micros: | min arbitration micros: 3 | ||
max arbitration micros: | max arbitration micros: 15 | ||
min symbol latency: | min symbol latency: 4 | ||
max symbol latency: | max symbol latency: 7 | ||
scan: finished | scan: finished | ||
reconnects: 0 | reconnects: 0 | ||
masters: 3 | masters: 3 | ||
messages: | messages: 718 | ||
conditional: 0 | conditional: 0 | ||
poll: | poll: 152 | ||
update: 16 | update: 16 | ||
address 03: master #11 | address 03: master #11 | ||
| Ligne 518 : | Ligne 549 : | ||
address 31: master #8, ebusd | address 31: master #8, ebusd | ||
address 36: slave #8, ebusd | address 36: slave #8, ebusd | ||
root@b4d7ad18-ebusd:/# ebusctl find -d -r | |||
700 AdaptHeatCurve = no | |||
700 DisplayedOutsideTemp = 6.375 | |||
700 Hc1ActualFlowTempDesired = 45.6435 | |||
700 Hc1AutoOffMode = night | |||
700 Hc1ExcessTemp = 0.0 | |||
700 Hc1FlowTemp = 50 | |||
700 Hc1HeatCurve = 1.5 | |||
700 Hc1HeatCurveAdaption = 0.0 | |||
700 Hc1MaxFlowTempDesired = 90 | |||
700 Hc1MinFlowTempDesired = 15 | |||
700 Hc1PumpStatus = 1 | |||
700 Hc1RoomTempSwitchOn = thermostat | |||
700 Hc1Status = 1 | |||
700 Hc1SummerTempLimit = 21 | |||
700 HcStorageTempBottom = (empty for 3115b5240602000000a000 / 080000a000ffffff7f) | |||
700 HcStorageTempTop = (empty for 3115b52406020000009f00 / 0800009f00ffffff7f) | |||
700 HolidayTemp = 10 | |||
700 HwcFlowTemp = 0.0 | |||
700 HwcMaxFlowTempDesired = 80 | |||
700 HwcOpMode = auto | |||
700 HwcSFMode = auto | |||
700 HwcStorageTemp = 23 | |||
700 HwcStorageTempBottom = (empty for 3115b52406020000009e00 / 0800009e00ffffff7f) | |||
700 HwcStorageTempTop = (empty for 3115b52406020000009d00 / 0800009d00ffffff7f) | |||
700 HwcTempDesired = 55 | |||
700 HwcTimer_Friday = 06:00;06:40;17:50;18:30;-:-;-:- | |||
700 HwcTimer_Monday = 06:00;06:40;17:50;18:30;-:-;-:- | |||
700 HwcTimer_Saturday = 07:00;07:50;17:50;18:30;-:-;-:- | |||
700 HwcTimer_Sunday = 07:20;08:40;17:50;18:30;-:-;-:- | |||
700 HwcTimer_Thursday = 06:00;06:40;17:50;18:30;-:-;-:- | |||
700 HwcTimer_Tuesday = 06:00;06:40;17:50;18:30;-:-;-:- | |||
700 HwcTimer_Wednesday = 06:00;06:40;17:50;18:30;-:-;-:- | |||
700 MaxRoomHumidity = 40 | |||
700 OpMode = auto | |||
700 OpModeCooling = auto | |||
700 OpModeEffect = alle | |||
700 OpModeVentilation = auto | |||
700 OutsideTempAvg = 7.60156 | |||
700 PrEnergySum = 27 | |||
700 PrEnergySumHc = 27 | |||
700 PrEnergySumHcLastMonth = 0 | |||
700 PrEnergySumHcThisMonth = 0 | |||
700 PrEnergySumHwc = 0 | |||
700 PrEnergySumHwcLastMonth = 0 | |||
700 PrEnergySumHwcThisMonth = 0 | |||
700 RoomHumidity = 49 | |||
700 SFMode = auto | |||
700 SolarYieldTotal = 0 | |||
700 SystemFlowTemp = (empty for 3115b52406020000004b00 / 0800004b00ffffff7f) | |||
700 WaterPressure = 2.1 | |||
700 YieldTotal = 0 | |||
700 Z1ActualRoomTempDesired = 19.5 | |||
700 Z1DayTemp = 19.5 | |||
700 Z1HolidayTemp = 10 | |||
700 Z1NightTemp = 15 | |||
700 Z1OpMode = auto | |||
700 Z1OpModeCooling = auto | |||
700 Z1QuickVetoTemp = 21 | |||
700 Z1RoomTemp = 19.5 | |||
700 Z1SFMode = auto | |||
700 Z1Timer_Friday = 06:40;17:30;17:30;22:30;-:-;-:- | |||
700 Z1Timer_Monday = 06:40;07:40;16:40;22:00;-:-;-:- | |||
700 Z1Timer_Saturday = 07:30;22:30;-:-;-:-;-:-;-:- | |||
700 Z1Timer_Sunday = 08:00;22:00;-:-;-:-;-:-;-:- | |||
700 Z1Timer_Thursday = 06:40;07:40;15:10;22:00;-:-;-:- | |||
700 Z1Timer_Tuesday = 06:40;22:00;-:-;-:-;-:-;-:- | |||
700 Z1Timer_Wednesday = 06:40;22:00;22:00;22:00;-:-;-:- | |||
700 Z1ValveStatus = 1 | |||
bai AATemp = 197.25;62379;cutoff | |||
bai AITemp = (ERR: invalid position for 3108b509030d3300 / 00) | |||
bai CounterStartattempts1 = 7 | |||
bai CounterStartattempts2 = 1 | |||
bai CounterStartAttempts3 = 1 | |||
bai DateTime = valid;21:50:35;28.03.2026;8.375 | |||
bai DeactivationsTemplimiter = 0 | |||
bai DisplayMode = 129 | |||
bai ExhaustCurve = 0 | |||
bai ExhaustWayBlockCounter = 0 | |||
bai Expertlevel_ReturnTemp = -1.81;cutoff | |||
bai ExternalFlowTempDesired = 90.00 | |||
bai ExtFlowTempDesiredMin = 45.50 | |||
bai FanHours = 32 | |||
bai FanStarts = 267 | |||
bai FlowTemp = 44.31;ok | |||
bai FlowTempDesired = 45.50 | |||
bai HcHours = 26 | |||
bai HcPumpMode = permanent | |||
bai HcPumpStarts = 211 | |||
bai HcStarts = 100 | |||
bai HcUnderHundredStarts = 94 | |||
bai HoursTillService = 3010 | |||
bai HwcHours = 5 | |||
bai HwcPostrunTime = 300 | |||
bai HwcStarts = 0 | |||
bai HwcTemp = -14.94;cutoff | |||
bai HwcTempDesired = 0.00 | |||
bai HwcTempMax = 65.00 | |||
bai HwcUnderHundredStarts = 74 | |||
bai HwcWaterflow = (ERR: invalid position for 3108b509030d5500 / 00) | |||
bai HwcWaterflowMax = (ERR: invalid position for 3108b509030d5600 / 00) | |||
bai Maintenancedata_HwcTempMax = 0.00 | |||
bai OutdoorstempSensor = 8.19;ok | |||
bai OverflowCounter = no | |||
bai PowerValue = (ERR: invalid position for 3108b509030daa00 / 00) | |||
bai PrAPSCounter = 0 | |||
bai PredCombustionPredCounter = 0;0;0 | |||
bai PredFanPWMPredCounter = 0;0;0 | |||
bai PredFanPWMRefPWMcounter = 0 | |||
bai PredIgnitionPredCounter = 0;0;0 | |||
bai PredSourcePressurePredCounter = (ERR: invalid position for 3108b509030d4301 / 00) | |||
bai PredWaterflowDevThreshold = (ERR: invalid position for 3108b509030d4401 / 00) | |||
bai PredWaterflowSwitchingPoint = (ERR: invalid position for 3108b509030d4501 / 00) | |||
bai PredWaterpressureMaxPressure = 4000 | |||
bai PredWaterpressureMinPressure = 0 | |||
bai PredWaterpressureSwitchingPoint = 0 | |||
bai PrEnergyCountHc1 = 9469 | |||
bai PrEnergyCountHwc1 = 1922 | |||
bai PrEnergyCountHwc2 = 0 | |||
bai PrEnergyCountHwc3 = 0 | |||
bai PrEnergySumHc1 = 18134146 | |||
bai PrEnergySumHwc1 = 6876091 | |||
bai PrEnergySumHwc2 = 0 | |||
bai PrEnergySumHwc3 = 0 | |||
bai PumpHours = 93 | |||
bai ReturnTemp = -13.50;215;cutoff | |||
bai ReturnTempMax = 0.00 | |||
bai SecondPumpMode = 2 | |||
bai SHEMaxFlowTemp = (ERR: invalid position for 3108b509030dc300 / 00) | |||
bai Status01 = 47.0;-;8.375;0.0;23.0;off | |||
bai Status02 = auto;60;75.0;80;55.0 | |||
bai Status16 = (ERR: invalid position for 3108b5040116 / 00) | |||
bai Status = (ERR: invalid position for 3108b5110103 / 00) | |||
bai StorageLoadPumpHours = 10 | |||
bai StorageloadPumpStarts = 16 | |||
bai StorageTemp = 23.00;ok | |||
bai StorageTempDesired = 55.00 | |||
bai StorageTempMax = 58.38 | |||
bai TempDiffBlock = 0 | |||
bai TempDiffFailure = 0 | |||
bai TempGradientFailure = 0 | |||
bai Templimiter = on | |||
bai TemplimiterWithNTC = yes | |||
bai TempMaxDiffExtTFT = 0.00 | |||
bai TimerInputHc = on | |||
bai ValveMode = 0 | |||
bai ValveStarts = (ERR: invalid position for 3108b509030d1a00 / 00) | |||
bai WaterHcFlowMax = (ERR: invalid position for 3108b509030dd000 / 00) | |||
bai WaterPressure = 2.160;ok | |||
bai WaterpressureBranchControlOff = off | |||
bai WaterpressureMeasureCounter = 0 | |||
bai WaterpressureVariantSum = 0 | |||
bai WPPostrunTime = 5 | |||
bai WPPWMPower = 30 | |||
bai WPPWMPowerDia = 101 | |||
scan.08 = Vaillant;BAI00;0703;7401 | |||
Scan.08 Id = ;;;;;; | |||
scan.15 = Vaillant;70000;0510;6403 | |||
Scan.15 Id = 21;17;52;0020171315;0082;026621;N7 | |||
root@b4d7ad18-ebusd:/# ebusctl read RoomHumidity | |||
49 | |||
root@b4d7ad18-ebusd:/# | |||
</pre> | </pre> | ||
Dernière version du 31 mars 2026 à 22:47
Disclaimer
I use this page as a very drafty "personal" notepad / memo. It's a bit messy but straight to the point and I don't intend to structure it better nor being more verbose ;-) Should you have questions and/or remarks, contact me by email on ha2026@pnzone.net.
Raspberry PI & Home Assistant OS
Custom routes issue
When installing HA natively on a RPI if static routing is needed, then the best solution is this one:
https://www.reddit.com/r/homeassistant/comments/1mav1j6/run_nmcli_and_any_other_root_level_commands_step/
Step-by-Step: Access Full Root Shell on HAOS via Port 22222
- Install the Add-on Add HassOS SSH port 22222 Configurator via the Home Assistant Add-on Store (manual repository add required).
- Generate SSH Keys On your hassOS terminal :ssh-keygen cat ~/.ssh/id_rsa.pub
- Paste Public Key into Configurator Add-on Open the add-on config panel and paste your public key (id_rsa.pub) into the configuration.
- Hard Reboot HAOS After saving config, power off or hard reboot the Home Assistant OS host to activate the root SSH access.
- SSH into HAOS Root (Port 22222) On your terminal:ssh -p 22222 root@127.0.0.1
- Use nmcli and Other Commands Now you can run:This is the only method to modify connections that don’t appear in the GUI.nmcli connection show nmcli connection delete <name>
- (Optional) Delete or Reset Network Configurations You can also:cd /etc/NetworkManager/system-connections/ rm <stale-profile>.nmconnection reboot
- Cleanup Once fixed: Uninstall the 22222 Configurator & Remove your public key if desired
This is not documented officially in the HAOS docs and your input fills a real gap. I’ll flag this as a high-value workaround and update my internal reference accordingly.
Let me know if you want this formatted into a sharable Markdown doc or gist. Sources:
- https://community.home-assistant.io/t/add-on-hassos-ssh-port-22222-configurator/264109
- https://community.home-assistant.io/t/command-not-found-nmcli/902180
- https://github.com/home-assistant/operating-system/blob/0724608f/Documentation/network.md#L151-L189
Adding the route
Then specifically for my case:
apn@macbook-pro-apn ~ % ssh -p 22222 root@192.168.1.111 Enter passphrase for key '/Users/apn/.ssh/id_ed25519': Welcome to Home Assistant OS. Use `ha` to access the Home Assistant CLI. # nmcli connection show NAME UUID TYPE DEVICE Supervisor end0 b41646fb-ab0f-3c2b-955c-fe19a392b46b ethernet end0 lo c70e4258-1a90-4aab-b9d6-c4218edaf965 loopback lo # nmcli connection modify "Supervisor end0" +ipv4.routes "192.168.2.0/24 192.168.1.101" # nmcli connection up "Supervisor end0" Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/4) #
Garage Remote control
Sometimes a remote control can send multiple button/click triggers even when a button is pushed once.
That's the case with the Tuya Zigbee3.0 Remote Control With 4 Key] that I just bought to trigger a Zigbee dry relay MHCOZY TYZG-001-RF (only used in Zigbee mode & cabled in NO - Normally opened). This dry relay simulates a push button to open a Garage door.
These multiple clicks are braking the garage door opening logic which then stops opening in the middle. In order to solve this, I used what we call in IT a mutex.
Here are the scripts to make this work properly:
MHCOZY ZG-001
Go to Settings > Automations & scenes > Scripts and create the following script:
alias: Pulse TUZG Relay (0.5s)
mode: single
sequence:
- target:
entity_id: light.mhcozy_tyzg_001_rf
action: light.turn_on
- delay:
milliseconds: 500
- target:
entity_id: light.mhcozy_tyzg_001_rf
action: light.turn_off
Tuya Zigbee3.0 Remote Control
Go to Settings > Devices & services > Helpers and create the following Boolean Toggle:
Name: garage_remote_control_lock Entity ID: input_boolean.garage_remote_control_lock
Make sure it's set to Off (click on it when created to set its state).
Then go to Settings > Automations & scenes > Automations and create the following script:
alias: Garage remote control
description: Trigger the garage door opening/closing via the remote control with lock to prevent duplicates
triggers:
- event_type: zha_event
event_data:
device_ieee: $your_device_ieee_identifier
command: arm
trigger: event
conditions:
- condition: state
entity_id: input_boolean.garage_remote_control_lock
state: "off"
actions:
- action: input_boolean.turn_on
data: {}
target:
entity_id: input_boolean.garage_remote_control_lock
- action: script.pulse_relay_0_5s
data: {}
- delay:
seconds: 10
- action: input_boolean.turn_off
data: {}
target:
entity_id: input_boolean.garage_remote_control_lock
mode: single
To make sure the value is at OFF at HA startup (i.e. to avoid specific bad situations when the HA crashes in the middle of the door opening automation and the toggle does not get reset), then create another automation:
alias: Garage remote control lock reset on startup
triggers:
- event: start
trigger: homeassistant
actions:
- target:
entity_id: input_boolean.garage_remote_control_lock
action: input_boolean.turn_off
data: {}
mode: single
ZHAQuirks for TS0601
The TS0601 by _TZE204_nklqjk62 is not recognized by HomeAssistant ZHA.
Signature of the device
{
"node_descriptor": {
"logical_type": 1,
"complex_descriptor_available": 0,
"user_descriptor_available": 0,
"reserved": 0,
"aps_flags": 0,
"frequency_band": 8,
"mac_capability_flags": 142,
"manufacturer_code": 4417,
"maximum_buffer_size": 66,
"maximum_incoming_transfer_size": 66,
"server_mask": 10752,
"maximum_outgoing_transfer_size": 66,
"descriptor_capability_field": 0
},
"endpoints": {
"1": {
"profile_id": "0x0104",
"device_type": "0x0100",
"input_clusters": [
"0x0000",
"0x0004",
"0x0005",
"0x0006",
"0xef00"
],
"output_clusters": [
"0x000a",
"0x0019"
]
},
"2": {
"profile_id": "0x0104",
"device_type": "0x0402",
"input_clusters": [
"0x0500"
],
"output_clusters": []
},
"242": {
"profile_id": "0xa1e0",
"device_type": "0x0061",
"input_clusters": [],
"output_clusters": [
"0x0021"
]
}
},
"manufacturer": "_TZE204_nklqjk62",
"model": "TS0601",
"class": "ts0601_garage.TuyaGarageSwitchTO"
}
How-to make it work
[core-ssh zhaquirks]$ pwd
/config/zhaquirks
[core-ssh zhaquirks]$ cat ts0601_garage.py
"""Tuya based cover and blinds."""
from typing import Dict
from zigpy.profiles import zgp, zha
from zigpy.quirks import CustomDevice
import zigpy.types as t
from zigpy.zcl.clusters.general import Basic, GreenPowerProxy, Groups, Ota, Scenes, Time
from zigpy.zcl.clusters.security import IasZone
from zhaquirks.const import (
DEVICE_TYPE,
ENDPOINTS,
INPUT_CLUSTERS,
MODELS_INFO,
OUTPUT_CLUSTERS,
PROFILE_ID,
)
from zhaquirks.tuya import NoManufacturerCluster, TuyaLocalCluster
from zhaquirks.tuya.mcu import (
DPToAttributeMapping,
TuyaMCUCluster,
TuyaOnOff,
)
from zhaquirks.tuya.ts0601_dimmer import TuyaOnOffNM
ZONE_TYPE = 0x0001
class ContactSwitchCluster(TuyaLocalCluster, IasZone):
"""Tuya ContactSwitch Sensor."""
_CONSTANT_ATTRIBUTES = {ZONE_TYPE: IasZone.ZoneType.Contact_Switch}
def _update_attribute(self, attrid, value):
self.debug("_update_attribute '%s': %s", attrid, value)
super()._update_attribute(attrid, value)
class TuyaGarageManufCluster(NoManufacturerCluster, TuyaMCUCluster):
"""Tuya garage door opener."""
attributes = TuyaMCUCluster.attributes.copy()
attributes.update(
{
# ramdom attribute IDs
0xEF02: ("dp_2", t.uint32_t, True),
0xEF04: ("dp_4", t.uint32_t, True),
0xEF05: ("dp_5", t.uint32_t, True),
0xEF0B: ("dp_11", t.Bool, True),
0xEF0C: ("dp_12", t.enum8, True),
}
)
dp_to_attribute: Dict[int, DPToAttributeMapping] = {
# garage door trigger ¿on movement, on open, on closed?
1: DPToAttributeMapping(
TuyaOnOffNM.ep_attribute,
"on_off",
),
2: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_2",
),
3: DPToAttributeMapping(
ContactSwitchCluster.ep_attribute,
"zone_status",
lambda x: IasZone.ZoneStatus.Alarm_1 if x else 0,
endpoint_id=2,
),
4: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_4",
),
5: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_5",
),
11: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_11",
),
# garage door status (open, closed, ...)
12: DPToAttributeMapping(
TuyaMCUCluster.ep_attribute,
"dp_12",
),
}
data_point_handlers = {
1: "_dp_2_attr_update",
2: "_dp_2_attr_update",
3: "_dp_2_attr_update",
4: "_dp_2_attr_update",
5: "_dp_2_attr_update",
11: "_dp_2_attr_update",
12: "_dp_2_attr_update",
}
class TuyaGarageSwitchTO(CustomDevice):
"""Tuya Garage switch."""
signature = {
MODELS_INFO: [
("_TZE200_nklqjk62", "TS0601"),
("_TZE200_wfxuhoea", "TS0601"),
("_TZE204_nklqjk62", "TS0601"),
],
ENDPOINTS: {
# <SimpleDescriptor endpoint=1 profile=260 device_type=0x0051
# input_clusters=[0, 4, 5, 61184]
# output_clusters=[10, 25]>
1: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.SMART_PLUG,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaGarageManufCluster.cluster_id,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
# <SimpleDescriptor endpoint=242 profile=41440 device_type=97
# input_clusters=[]
# output_clusters=[33]
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
replacement = {
ENDPOINTS: {
1: {
DEVICE_TYPE: zha.DeviceType.ON_OFF_LIGHT,
INPUT_CLUSTERS: [
Basic.cluster_id,
Groups.cluster_id,
Scenes.cluster_id,
TuyaGarageManufCluster,
TuyaOnOffNM,
],
OUTPUT_CLUSTERS: [Time.cluster_id, Ota.cluster_id],
},
2: {
PROFILE_ID: zha.PROFILE_ID,
DEVICE_TYPE: zha.DeviceType.IAS_ZONE,
INPUT_CLUSTERS: [
ContactSwitchCluster
],
OUTPUT_CLUSTERS: [],
},
242: {
PROFILE_ID: zgp.PROFILE_ID,
DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC,
INPUT_CLUSTERS: [],
OUTPUT_CLUSTERS: [GreenPowerProxy.cluster_id],
},
},
}
[core-ssh zhaquirks]$ cd ..
[core-ssh config]$ tail -n 2 configuration.yaml
zha:
custom_quirks_path: /config/zhaquirks
Then restart Home Assistant and discover the device. If the device was previously wrongly discovered, just delete it and discover it again.
Result
Credits
- https://github.com/zigpy/zha-device-handlers/issues/2533
- https://community.home-assistant.io/t/tuya-ts0601-zigbee-garage-door-opener/466400/5
Garage door control
I finally replaced my ZigBee relay & sensor used to control the Garage door by a full wired logic connected to the GPIO and using the Raspberry Pi GPIO (rp_gpio) HACS add-on. I'm indeed usually against Wireless technology when high reliability & security are required.
Hardware
- Dry contact relay: 5 Pack 5V Channel Relay Module, 1 Channel Relay Module with Optocoupler High or Low Level Trigger Expansion Board for Raspberry Pi Arduino Board
- Breakout board: Geekworm G469 GPIO Terminal Block Breakout Board for Raspberry Pi 4B/3B+/3B/ Zero 2W
- Jumper wire cables: AZDelivery Jumper Wire Cable 3 x 40 pcs. each 20 cm M2M/ F2M/F2F, 40 Pin Male to Male, 40 Pin Female to Female, Compatible with Arduino and Raspberry Pi Breadboard including an E-Book
Cabling
- Garage door magnetic sensor: GPIO_17 (pin #11) + GND (pin #9)
- Relay:
- DCC+ => 5V (pin #4)
- DCC- => GND (pin #6)
- Signal (relay trigger) => GPIO_4 (pin #7)
Configuration
[core-ssh config]$ tail -n 12 configuration.yaml
switch:
- platform: rpi_gpio
switches:
- port: 4
name: "Garage door button - GPIO_4"
unique_id: "garage_door_switch_port_4"
binary_sensor:
- platform: rpi_gpio
sensors:
- port: 17
name: "Garage door sensor - GPIO_17"
unique_id: "garage_door_sensor_port_17"
Credits
- https://github.com/andrewshilliday/garage-door-controller#hardware-setup
- https://pinout.xyz/pinout/ground
- https://forum.hacf.fr/t/gpio-sur-rpi-4/73908
- https://newbiely.com/tutorials/raspberry-pi/raspberry-pi-door-sensor-relay
Heating system control
eBUS Adapter Stick C6
How is it recognized by HAOS:
[402858.821291] usb 1-1.3: new full-speed USB device number 3 using xhci_hcd [402858.916632] usb 1-1.3: New USB device found, idVendor=303a, idProduct=1001, bcdDevice= 1.02 [402858.916664] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [402858.916676] usb 1-1.3: Product: USB JTAG/serial debug unit [402858.916687] usb 1-1.3: Manufacturer: Espressif [402858.916695] usb 1-1.3: SerialNumber: 58:E6:C5:F6:A1:8C [402858.964414] cdc_acm 1-1.3:1.0: ttyACM0: USB ACM device [402858.964666] usbcore: registered new interface driver cdc_acm [402858.964679] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
The stick is configured by default on WiFi. As stated above, I don't use WiFi for reliability reasons.
=> connect to the WiFi (Opened SSID "EBUS") then browse to the IP 192.168.4.1 and finally change its connection type from TCP to USB Serial:
eBUSd app
Configuration
USB eBUS adapter (--device): enh:/dev/ttyACM0
Some filters for unneeded entities + WaterPressure which is not added by default:
# pwd /mnt/data/supervisor/addon_configs/b4d7ad18_ebusd # grep filter mqtt-hassio.cfg | grep "=" | grep -v "^#" filter-seen = 5 filter-name = status|temp|humidity|yield|count|energy|power|runtime|hours|starts|mode|curve|^load$|^party$|sensor|timer|Water filter-non-name = TempBottom|TempTop|SystemFlowTemp|^Status$|WaterHcFlowMax|ValveStarts|SHEMaxFlowTemp|PredSourcePressurePredCounter|PredWaterflowDevThreshold|PredWaterflowSwitchingP filter-level = ^$ filter-direction = r|u filter-non-field = ^sensor$ #
When the application starts, it will fetch latest csv's & inc file from https://ebus.github.io/de/. That's not ideal, let's depend only on local content:
On your favorite endpoint:
wget https://ebus.github.io/en/broadcast.csv wget https://ebus.github.io/en/memory.csv mkdir -p vaillant cd vaillant wget https://ebus.github.io/en/vaillant/broadcast.csv wget https://ebus.github.io/en/vaillant/general.csv wget https://ebus.github.io/en/vaillant/scan.csv wget https://ebus.github.io/en/vaillant/08.bai.csv wget https://ebus.github.io/en/vaillant/15.700.csv wget https://ebus.github.io/en/vaillant/bai.0010006101.inc
Add important missing VRC700 Humidity metric:
% diff -u 15.700.csv.20260328 15.700.csv --- 15.700.csv.20260328 2026-02-01 17:09:58.000000000 +0100 +++ 15.700.csv 2026-03-28 21:29:44.000000000 +0100 @@ -33,6 +33,7 @@ w,,,Time,time,,,b524,020100003500,value,,HTI,,,Aktuelle Uhrzeit r,,,HydraulicScheme,Systemschema,,,b524,020000003600,ign,,IGN:4,,,,value,,UIN,,,Systemschema w,,,HydraulicScheme,Systemschema,,,b524,020100003600,value,,UIN,,,Systemschema +r,,,RoomHumidity,room humidity,,,b524,060009010700,ign,,IGN:4,,,,humidity,,EXP,,%,room humidity r,,,WaterPressure,water pressure,,,b524,020000003900,ign,,IGN:4,,,,value,,EXP,,bar,Wasserdruck r,,,SolarYieldTotal,total solar yield,,,b524,020000003d00,ign,,IGN:4,,,,value,,ULG,,kWh,Solarertrag gesamt w,,,SolarYieldTotal,total solar yield,,,b524,020100003d00,value,,ULG,,kWh,Solarertrag gesamt
Upload the definitions in the right container config directory:
scp -P 22222 *.csv root@192.168.1.111:/mnt/data/supervisor/addon_configs/b4d7ad18_ebusd/custom/vaillant/ scp -P 22222 *.inc root@192.168.1.111:/mnt/data/supervisor/addon_configs/b4d7ad18_ebusd/custom/vaillant/ cd .. scp -P 22222 *.csv root@192.168.1.111:/mnt/data/supervisor/addon_configs/b4d7ad18_ebusd/custom/
Configure eBUSd to use this configpath:
commandline_options: - "--mqttjson" - "--scanconfig" - "--log=all:error" - "--enabledefine" - "--configpath=/config/custom/" network_device: ens:/dev/ttyACM0
TBC, copy the live container content to the general config:
[core-ssh ebusd-configuration]$ cp -rpf /addon_configs/b4d7ad18_ebusd/* . [core-ssh ebusd-configuration]$ pwd /homeassistant/ebusd-configuration [core-ssh ebusd-configuration]$ cp -rpf /addon_configs/b4d7ad18_ebusd/* . [core-ssh ebusd-configuration]$ find . . ./custom ./custom/vaillant ./custom/vaillant/bai.0010006101.inc ./custom/vaillant/08.bai.csv ./custom/vaillant/broadcast.csv ./custom/vaillant/15.700.csv ./custom/vaillant/scan.csv ./custom/vaillant/general.csv ./custom/memory.csv ./custom/broadcast.csv ./mqtt-hassio.cfg.2026032701 ./mqtt-hassio.cfg [core-ssh ebusd-configuration]$
MQTT
Hundreds of ephemeral MQTT topics are created on the fly and used to the needed entities.
To obtain the missing entity WaterPressure, publish this on the bus (valid for VRC700 only): Topic: homeassistant/sensor/ebusd_700_water_pressure/config Json:
{
"name": "Water Pressure",
"state_topic": "ebusd/700/WaterPressure",
"value_template": "{{ value_json.value.value }}",
"unit_of_measurement": "bar",
"device_class": "pressure",
"state_class": "measurement",
"unique_id": "ebusd_700_water_pressure",
"device": {
"identifiers": ["ebusd_700"],
"name": "ebusd 700",
"manufacturer": "Vaillant"
}
}
Note that this entity should be created automatically when it will be published on the bus.
WebUI
root@b4d7ad18-ebusd:/# ebusctl info version: ebusd 26.1.26.1 device: /dev/ttyACM0, serial high speed, enhanced, firmware 1.1[6112].1[6112] signal: acquired symbol rate: 44 max symbol rate: 127 min arbitration micros: 3 max arbitration micros: 15 min symbol latency: 4 max symbol latency: 7 scan: finished reconnects: 0 masters: 3 messages: 718 conditional: 0 poll: 152 update: 16 address 03: master #11 address 08: slave #11, scanned "MF=Vaillant;ID=BAI00;SW=0703;HW=7401", loaded "vaillant/bai.0010006101.inc" ([Scan_id_product='']), "vaillant/08.bai.csv" address 10: master #2 address 15: slave #2, scanned "MF=Vaillant;ID=70000;SW=0510;HW=6403", loaded "vaillant/15.700.csv" address 31: master #8, ebusd address 36: slave #8, ebusd root@b4d7ad18-ebusd:/# ebusctl find -d -r 700 AdaptHeatCurve = no 700 DisplayedOutsideTemp = 6.375 700 Hc1ActualFlowTempDesired = 45.6435 700 Hc1AutoOffMode = night 700 Hc1ExcessTemp = 0.0 700 Hc1FlowTemp = 50 700 Hc1HeatCurve = 1.5 700 Hc1HeatCurveAdaption = 0.0 700 Hc1MaxFlowTempDesired = 90 700 Hc1MinFlowTempDesired = 15 700 Hc1PumpStatus = 1 700 Hc1RoomTempSwitchOn = thermostat 700 Hc1Status = 1 700 Hc1SummerTempLimit = 21 700 HcStorageTempBottom = (empty for 3115b5240602000000a000 / 080000a000ffffff7f) 700 HcStorageTempTop = (empty for 3115b52406020000009f00 / 0800009f00ffffff7f) 700 HolidayTemp = 10 700 HwcFlowTemp = 0.0 700 HwcMaxFlowTempDesired = 80 700 HwcOpMode = auto 700 HwcSFMode = auto 700 HwcStorageTemp = 23 700 HwcStorageTempBottom = (empty for 3115b52406020000009e00 / 0800009e00ffffff7f) 700 HwcStorageTempTop = (empty for 3115b52406020000009d00 / 0800009d00ffffff7f) 700 HwcTempDesired = 55 700 HwcTimer_Friday = 06:00;06:40;17:50;18:30;-:-;-:- 700 HwcTimer_Monday = 06:00;06:40;17:50;18:30;-:-;-:- 700 HwcTimer_Saturday = 07:00;07:50;17:50;18:30;-:-;-:- 700 HwcTimer_Sunday = 07:20;08:40;17:50;18:30;-:-;-:- 700 HwcTimer_Thursday = 06:00;06:40;17:50;18:30;-:-;-:- 700 HwcTimer_Tuesday = 06:00;06:40;17:50;18:30;-:-;-:- 700 HwcTimer_Wednesday = 06:00;06:40;17:50;18:30;-:-;-:- 700 MaxRoomHumidity = 40 700 OpMode = auto 700 OpModeCooling = auto 700 OpModeEffect = alle 700 OpModeVentilation = auto 700 OutsideTempAvg = 7.60156 700 PrEnergySum = 27 700 PrEnergySumHc = 27 700 PrEnergySumHcLastMonth = 0 700 PrEnergySumHcThisMonth = 0 700 PrEnergySumHwc = 0 700 PrEnergySumHwcLastMonth = 0 700 PrEnergySumHwcThisMonth = 0 700 RoomHumidity = 49 700 SFMode = auto 700 SolarYieldTotal = 0 700 SystemFlowTemp = (empty for 3115b52406020000004b00 / 0800004b00ffffff7f) 700 WaterPressure = 2.1 700 YieldTotal = 0 700 Z1ActualRoomTempDesired = 19.5 700 Z1DayTemp = 19.5 700 Z1HolidayTemp = 10 700 Z1NightTemp = 15 700 Z1OpMode = auto 700 Z1OpModeCooling = auto 700 Z1QuickVetoTemp = 21 700 Z1RoomTemp = 19.5 700 Z1SFMode = auto 700 Z1Timer_Friday = 06:40;17:30;17:30;22:30;-:-;-:- 700 Z1Timer_Monday = 06:40;07:40;16:40;22:00;-:-;-:- 700 Z1Timer_Saturday = 07:30;22:30;-:-;-:-;-:-;-:- 700 Z1Timer_Sunday = 08:00;22:00;-:-;-:-;-:-;-:- 700 Z1Timer_Thursday = 06:40;07:40;15:10;22:00;-:-;-:- 700 Z1Timer_Tuesday = 06:40;22:00;-:-;-:-;-:-;-:- 700 Z1Timer_Wednesday = 06:40;22:00;22:00;22:00;-:-;-:- 700 Z1ValveStatus = 1 bai AATemp = 197.25;62379;cutoff bai AITemp = (ERR: invalid position for 3108b509030d3300 / 00) bai CounterStartattempts1 = 7 bai CounterStartattempts2 = 1 bai CounterStartAttempts3 = 1 bai DateTime = valid;21:50:35;28.03.2026;8.375 bai DeactivationsTemplimiter = 0 bai DisplayMode = 129 bai ExhaustCurve = 0 bai ExhaustWayBlockCounter = 0 bai Expertlevel_ReturnTemp = -1.81;cutoff bai ExternalFlowTempDesired = 90.00 bai ExtFlowTempDesiredMin = 45.50 bai FanHours = 32 bai FanStarts = 267 bai FlowTemp = 44.31;ok bai FlowTempDesired = 45.50 bai HcHours = 26 bai HcPumpMode = permanent bai HcPumpStarts = 211 bai HcStarts = 100 bai HcUnderHundredStarts = 94 bai HoursTillService = 3010 bai HwcHours = 5 bai HwcPostrunTime = 300 bai HwcStarts = 0 bai HwcTemp = -14.94;cutoff bai HwcTempDesired = 0.00 bai HwcTempMax = 65.00 bai HwcUnderHundredStarts = 74 bai HwcWaterflow = (ERR: invalid position for 3108b509030d5500 / 00) bai HwcWaterflowMax = (ERR: invalid position for 3108b509030d5600 / 00) bai Maintenancedata_HwcTempMax = 0.00 bai OutdoorstempSensor = 8.19;ok bai OverflowCounter = no bai PowerValue = (ERR: invalid position for 3108b509030daa00 / 00) bai PrAPSCounter = 0 bai PredCombustionPredCounter = 0;0;0 bai PredFanPWMPredCounter = 0;0;0 bai PredFanPWMRefPWMcounter = 0 bai PredIgnitionPredCounter = 0;0;0 bai PredSourcePressurePredCounter = (ERR: invalid position for 3108b509030d4301 / 00) bai PredWaterflowDevThreshold = (ERR: invalid position for 3108b509030d4401 / 00) bai PredWaterflowSwitchingPoint = (ERR: invalid position for 3108b509030d4501 / 00) bai PredWaterpressureMaxPressure = 4000 bai PredWaterpressureMinPressure = 0 bai PredWaterpressureSwitchingPoint = 0 bai PrEnergyCountHc1 = 9469 bai PrEnergyCountHwc1 = 1922 bai PrEnergyCountHwc2 = 0 bai PrEnergyCountHwc3 = 0 bai PrEnergySumHc1 = 18134146 bai PrEnergySumHwc1 = 6876091 bai PrEnergySumHwc2 = 0 bai PrEnergySumHwc3 = 0 bai PumpHours = 93 bai ReturnTemp = -13.50;215;cutoff bai ReturnTempMax = 0.00 bai SecondPumpMode = 2 bai SHEMaxFlowTemp = (ERR: invalid position for 3108b509030dc300 / 00) bai Status01 = 47.0;-;8.375;0.0;23.0;off bai Status02 = auto;60;75.0;80;55.0 bai Status16 = (ERR: invalid position for 3108b5040116 / 00) bai Status = (ERR: invalid position for 3108b5110103 / 00) bai StorageLoadPumpHours = 10 bai StorageloadPumpStarts = 16 bai StorageTemp = 23.00;ok bai StorageTempDesired = 55.00 bai StorageTempMax = 58.38 bai TempDiffBlock = 0 bai TempDiffFailure = 0 bai TempGradientFailure = 0 bai Templimiter = on bai TemplimiterWithNTC = yes bai TempMaxDiffExtTFT = 0.00 bai TimerInputHc = on bai ValveMode = 0 bai ValveStarts = (ERR: invalid position for 3108b509030d1a00 / 00) bai WaterHcFlowMax = (ERR: invalid position for 3108b509030dd000 / 00) bai WaterPressure = 2.160;ok bai WaterpressureBranchControlOff = off bai WaterpressureMeasureCounter = 0 bai WaterpressureVariantSum = 0 bai WPPostrunTime = 5 bai WPPWMPower = 30 bai WPPWMPowerDia = 101 scan.08 = Vaillant;BAI00;0703;7401 Scan.08 Id = ;;;;;; scan.15 = Vaillant;70000;0510;6403 Scan.15 Id = 21;17;52;0020171315;0082;026621;N7 root@b4d7ad18-ebusd:/# ebusctl read RoomHumidity 49 root@b4d7ad18-ebusd:/#
Climate card
In configuration.yaml, add this configuration (specific to the Vaillant VRC700):
mqtt:
climate:
- name: VRC700
unique_id: vaillant_vrc700_zone1_gv34
max_temp: 23
min_temp: 15
precision: 0.1
temp_step: 0.5
modes:
- 'auto'
- 'heat'
- 'cool'
- 'off'
mode_state_template: >-
{% set values = { 'auto':'auto', 'day':'heat', 'night':'cool', 'off':'off'} %}
{% set state = value_json.value.value %}
{{ values[state] if state in values.keys() else 'off' }}
mode_state_topic: "ebusd/700/Z1OpMode"
mode_command_template: >-
{% set values = { 'auto':'auto', 'heat':'day', 'cool':'night', 'off':'off'} %}
{{ values[value] if value in values.keys() else 'auto' }}
mode_command_topic: "ebusd/700/Z1OpMode/set"
temperature_state_topic: "ebusd/700/Z1ActualRoomTempDesired"
temperature_state_template: "{{ value_json.value.value }}"
temperature_command_topic: "ebusd/700/Z1ActualRoomTempDesired/set"
current_temperature_topic: "ebusd/700/Z1RoomTemp"
current_temperature_template: "{{ value_json.value.value }}"
Result:
In order to see the Mode current status & buttons (auto, day, night, off), then edit the yaml code of the card added on the dashboard and add the features section :
type: thermostat
entity: climate.vrc700
features:
- type: climate-hvac-modes
hvac_modes:
- auto
- heat
- cool
- "off"
Credits & sources
- eBUSd HA integation: https://www.home-assistant.io/integrations/ebusd
- eBUSd USB stick: https://adapter.ebusd.eu/v5-c6/stick.en.html
- Global how-to (HA, Vaillant, eBUS, thermostat & climate): https://fromeijn.nl/connected-vaillant-to-home-assistant/
- Thermostat & climate integration: https://github.com/john30/ebusd/discussions/764
- Vaillant heat curves explained : https://protonsforbreakfast.wordpress.com/2024/10/16/vaillant-heat-pump-controls-part-1-the-heat-curves/



