optolink-bridge 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +10 -0
- package/.gitattributes +4 -0
- package/.vscode/extensions.json +5 -0
- package/.vscode/settings.json +11 -0
- package/.yarn/sdks/integrations.yml +5 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +13 -0
- package/README.md +429 -0
- package/config.toml +292 -0
- package/discovery.js +74 -0
- package/docs/device_list.pdf +0 -0
- package/docs/intercept-mode.png +0 -0
- package/docs/logo.png +0 -0
- package/docs/packet-flow.png +0 -0
- package/docs/pass-through-mode.png +0 -0
- package/docs/raspberry-pi-cp2102.png +0 -0
- package/index.js +317 -0
- package/package.json +63 -0
- package/parse_vs2.js +249 -0
- package/serial.js +88 -0
- package/tools/analyze_trace.js +486 -0
- package/tools/analyze_trace_example.txt +671 -0
- package/tools/convert_data_points.js +86 -0
- package/tools/convert_data_points_example.txt +3198 -0
- package/tools/convert_poll_items.js +91 -0
- package/tools/convert_poll_items_example.txt +42 -0
- package/utils.js +141 -0
package/config.toml
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# serial port of the Vitoconnect device, defaults to "/dev/ttyS0", Raspberry 3B+ (and some others) use "/dev/ttyAMA0"
|
|
2
|
+
port_vito = "/dev/ttyS0"
|
|
3
|
+
# serial port of the Optolink adapter / device, defaults to "/dev/ttyUSB0"
|
|
4
|
+
port_opto = "/dev/ttyUSB0"
|
|
5
|
+
|
|
6
|
+
# log level, one of "none", "error", "warn", "info", "trace" or "verbose" defaults to "warn"
|
|
7
|
+
# note: this setting may be changed during runtime and is picked up from this file automatically
|
|
8
|
+
log_level = "warn"
|
|
9
|
+
|
|
10
|
+
# data points to listen to and publish
|
|
11
|
+
# (use tools/convert_poll_items.js to convert your existing optolink-splitter poll_list to data_points)
|
|
12
|
+
data_points = [
|
|
13
|
+
# [name, addr, [type], [scale]]
|
|
14
|
+
# name: name of the data point, as published
|
|
15
|
+
# addr: address of the data point, either as hexadecimal 0xab01 or as decimal 43873
|
|
16
|
+
# type:
|
|
17
|
+
# "raw" for raw data (0x..., alias for buffer)
|
|
18
|
+
# "int" / "uint" for integer values matching the size of the data (e.g. (u)int16 for 2 bytes)
|
|
19
|
+
# corner case: 3 byte values are mapped to (u)int16 and 5 byte values to (u)int32
|
|
20
|
+
# due to a many numerical data points having a trailing status byte that is ignored
|
|
21
|
+
# "byte" for a single byte value (alias for uint8)
|
|
22
|
+
# "vdatetime" for Viessmann specific date and time values
|
|
23
|
+
# "unixtime" for unix timestamps
|
|
24
|
+
# "utf8" for utf8 encoded strings
|
|
25
|
+
# or any data types supported by binary-parser (e.g. uint16)
|
|
26
|
+
# note that byte-bit filters are *not* yet supported
|
|
27
|
+
# scale: a factor to scale the numeric value by, e.g. 0.1 to convert 100 to 10.0
|
|
28
|
+
# if type is set to a number, the data point is treated as a integer matching the size of the data (e.g. (u)int16
|
|
29
|
+
# for 2 bytes), the number represents the scale, scale can the be set to true, to indicate a signed number
|
|
30
|
+
# if no type is given, the data point is treated as a raw
|
|
31
|
+
|
|
32
|
+
["outside_temperature", 0x01C1, "int16", 0.1], # 3 bytes (sensor temp. w/ status), 2 bytes as 0x0101, but not sent by Vitoconnect
|
|
33
|
+
["averaged_outside_temperature", 0x160D, "int16", 0.1],
|
|
34
|
+
["averaging_time_outside_temperature", 0x7002, "int16"],
|
|
35
|
+
|
|
36
|
+
["operating_mode", 0xB000, "byte"],
|
|
37
|
+
|
|
38
|
+
["heating_circuit_circulation_pump", 0x048D, "byte"],
|
|
39
|
+
["secondary_pump", 0x0484, "byte"],
|
|
40
|
+
|
|
41
|
+
["hkl_level", 0x2006, "int16", 0.1],
|
|
42
|
+
["hkl_slope", 0x2007, "int16", 0.1],
|
|
43
|
+
["hysteresis", 0x6007, "int16", 0.1], # also as 0x7203, but not sent by Vitoconnect
|
|
44
|
+
|
|
45
|
+
["buffer_temperature", 0x01CB, "int16", 0.1], # 3 bytes (sensor temp. w/ status), 2 bytes as 0x010B, but not sent by Vitoconnect
|
|
46
|
+
|
|
47
|
+
["primary_circuit_flow_temperature", 0xb400, "int16", 0.1], # 3 bytes (sensor temp. w/ status), 2 bytes as 0x0103, but not sent by Vitoconnect
|
|
48
|
+
["secondary_circuit_flow_temperature", 0xb402, "int16", 0.1], # 3 bytes (sensor temp. w/ status), 2 bytes as 0x0105, but not sent by Vitoconnect
|
|
49
|
+
["return_temperature", 0x01c6, "int16", 0.1], # 3 bytes (sensor temp. w/ status), 2 bytes as 0x0106, but not sent by Vitoconnect
|
|
50
|
+
|
|
51
|
+
["3way_valve_position", 0x0494, "byte"],
|
|
52
|
+
|
|
53
|
+
["suction_gas_temperature", 0xb409, "int16", 0.1],
|
|
54
|
+
["suction_gas_pressure", 0xb410, "int16", 0.1],
|
|
55
|
+
["hot_gas_temperature", 0xb40a, "int16", 0.1],
|
|
56
|
+
["hot_gas_pressure", 0xb411, "int16", 0.1],
|
|
57
|
+
["liquid_gas_temperature", 0xb404, "int16", 0.1],
|
|
58
|
+
["condensation_temperature", 0xb408, "int16", 0.1],
|
|
59
|
+
["evaporation_temperature", 0xb407, "int16", 0.1],
|
|
60
|
+
["compressor_power", 0xb423, "uint8"],
|
|
61
|
+
["ecv_position", 0xb424, "uint8"],
|
|
62
|
+
|
|
63
|
+
["dhw_temperature_storage", 0x01CD, "int16", 0.1], # 3 bytes (sensor temp. w/ status), 2 bytes as 0x010D, but not sent by Vitoconnect
|
|
64
|
+
["dhw_temperature_setpoint", 0x6000, "int16", 0.1],
|
|
65
|
+
["dhw_temperature_setpoint2", 0x600C, "int16", 0.1],
|
|
66
|
+
["dhw_circulation_pump", 0x0490, "byte"],
|
|
67
|
+
|
|
68
|
+
#["room_temperature_setpoint_actual", 0x0116, "int16", 0.1],
|
|
69
|
+
#["room_temperature_setpoint_set", 0x011B, "int16", 0.1],
|
|
70
|
+
["room_temperature_setpoint_normal", 0x2000, "int16", 0.1],
|
|
71
|
+
["room_temperature_setpoint_reduced", 0x2001, "int16", 0.1],
|
|
72
|
+
["room_temperature_setpoint_party", 0x2022, "int16", 0.1],
|
|
73
|
+
|
|
74
|
+
["compressor_phase", 0x0E1A, "byte"], # V1AppState, undocumented 0x130B is used by Vitoconnect
|
|
75
|
+
["compressor_starts", 0x0500, "int32"],
|
|
76
|
+
["compressor_operating_hours", 0x0580, "uint32", 0.0002777777777777778],
|
|
77
|
+
["compressor_heating_power", 0x16A0, "uint"],
|
|
78
|
+
["compressor_power_consumption", 0x16A4, "uint"],
|
|
79
|
+
|
|
80
|
+
["one_time_dhw", 0xB020, "byte"],
|
|
81
|
+
|
|
82
|
+
["energy_balance_factor", 0x163F, "int8"],
|
|
83
|
+
["energy_balance_heating", 0x1640, "uint32"],
|
|
84
|
+
["energy_balance_dhw", 0x1650, "uint32"],
|
|
85
|
+
["energy_balance_heating_electric", 0x1660, "uint32"],
|
|
86
|
+
["energy_balance_dhw_electric", 0x1670, "uint32"],
|
|
87
|
+
|
|
88
|
+
["annual_performance_factor", 0x1680, "int8", 0.1],
|
|
89
|
+
["annual_performance_factor_heating", 0x1681, "int8", 0.1],
|
|
90
|
+
["annual_performance_factor_dhw", 0x1682, "int8", 0.1],
|
|
91
|
+
|
|
92
|
+
["auxiliary_heater_enable", 0x6014, "byte"],
|
|
93
|
+
["electric_heater_enable", 0x6015, "byte"]
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
# if set (and not empty), the items in this list are polled at the specified intervals
|
|
97
|
+
# note: setting a poll_items list, results in optolink-bridge being started in "intercept" mode
|
|
98
|
+
# if not set, a PassThrough stream will be used to forward the data from the Optolink bus, if set
|
|
99
|
+
# a Transform stream will be used instead, to inject the poll items into the communication
|
|
100
|
+
poll_items = [
|
|
101
|
+
# [ival, addr, dlen]
|
|
102
|
+
# ival: the interval in seconds to poll the item
|
|
103
|
+
# warning: the Optolink serial port is using quite a low baud rate of 4800 bauds / bytes, which
|
|
104
|
+
# (with parity bits included, and assuming the average packet size) results in about 20-25 packets
|
|
105
|
+
# that are transmitted via the bus each second. this includes requests and responses, meaning that only
|
|
106
|
+
# about 10-12 requests can be sent per second before the bus becomes saturated. optolink-bridge will
|
|
107
|
+
# only inject one poll request per message sent to the Optolink bus, meaning the maximum polling rate of
|
|
108
|
+
# items is about 5-6 items per second, reducing the Optolink bus throughput in half. thus the intervals
|
|
109
|
+
# in the poll_items list should be set accordingly. say you have 10 items that you each want to poll every
|
|
110
|
+
# second, the polling queue will become over saturated quickly and a warning will be logged to console
|
|
111
|
+
# addr: the address to poll
|
|
112
|
+
# dlen: the length of data to poll, note that your heating device will likely respond with a NAK / ERR, in
|
|
113
|
+
# in case the length of the data is not specified as the address / data type defines it
|
|
114
|
+
[15, 0xb408, 3], # condensation_temperature
|
|
115
|
+
[15, 0xb407, 3] # evaporation_temperature
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
# the format to publish raw / byte / buffer data, defaults to "hex", one of:
|
|
119
|
+
# "id" or "identity" (publish binary data to MQTT)
|
|
120
|
+
# "hex" or "hex_upper" (lower/upper case hex string)
|
|
121
|
+
# "0x" or "0x_upper" (lower/upper case hex string with 0x prefix)
|
|
122
|
+
# "base64" (base64 encoded string)
|
|
123
|
+
buffer_format = "hex"
|
|
124
|
+
# the maximum number of decimals to round to on publish, defaults to 4
|
|
125
|
+
max_decimals = 4
|
|
126
|
+
|
|
127
|
+
# automatically reload data points and poll items from this configuration file if file changes are detected,
|
|
128
|
+
# without (!) interrupting the active Vitoconnect / Optolink communication, defaults to true
|
|
129
|
+
# note: this setting only affects reloading data points and poll list items, other changes might not be picked up
|
|
130
|
+
# also poll_items will only refresh, in case the list was populated, when you started optolink-bridge
|
|
131
|
+
# in case you add a item to the (previously empty) poll_items list, you will need to restart optolink-bridge
|
|
132
|
+
# (this is because if poll_items is empty, optolink-bridge will start in pass-through mode and is not able to intercept messages)
|
|
133
|
+
auto_reload_addr_items = true
|
|
134
|
+
|
|
135
|
+
[mqtt]
|
|
136
|
+
|
|
137
|
+
# broker protocol / host / port
|
|
138
|
+
url = "mqtt://127.0.0.1:1883"
|
|
139
|
+
# broker username
|
|
140
|
+
username = "user"
|
|
141
|
+
# broker password
|
|
142
|
+
password = "password"
|
|
143
|
+
# base topic to publish attributes to, defaults to "Vito"
|
|
144
|
+
# e.g.: Vito/<dpname>
|
|
145
|
+
topic = "Vito"
|
|
146
|
+
# suffix to append to the topic, defaults to <dpname>
|
|
147
|
+
# allowed wildcards are <addr> (or <dpaddr> as alias) and <dpname>
|
|
148
|
+
suffix = "<dpname>"
|
|
149
|
+
# retain a "online" topic, e.g. Vito/online, defaults to true / "online", set to a string to use a different topic
|
|
150
|
+
# note: if set to false, home assistant will not be able to determine if the devices / entities are available
|
|
151
|
+
online = true
|
|
152
|
+
|
|
153
|
+
# publish unknown data points to MQTT as raw data
|
|
154
|
+
publish_unknown_dps = false
|
|
155
|
+
# the suffix to use to publish unknown data points, defaults to "raw/<addr>"
|
|
156
|
+
unknown_dp_suffix = "raw/<addr>"
|
|
157
|
+
|
|
158
|
+
[mqtt.options]
|
|
159
|
+
# other broker options (see https://github.com/mqttjs/MQTT.js?tab=readme-ov-file#client options)
|
|
160
|
+
#...
|
|
161
|
+
|
|
162
|
+
[mqtt.device_discovery]
|
|
163
|
+
|
|
164
|
+
# set to false to disable publishing a device discovery payload
|
|
165
|
+
enabled = true
|
|
166
|
+
|
|
167
|
+
# the discovery prefix for devices, defaults to "homeassistant"
|
|
168
|
+
prefix = "homeassistant"
|
|
169
|
+
|
|
170
|
+
# optolink-bridge publishes a single device discovery payload, see:
|
|
171
|
+
# https://www.home-assistant.io/integrations/mqtt/#device-discovery-payload
|
|
172
|
+
|
|
173
|
+
# by default all data_points will be published as basic sensors, you may use the next section(s) to override specific
|
|
174
|
+
# settings of the discovery payload, for example to set device classes, icons, units, etc., see the home assistant
|
|
175
|
+
# mqtt integration documentation for details. note that all overrides must be specified in their non-abbreviated form
|
|
176
|
+
|
|
177
|
+
[mqtt.device_discovery.overrides]
|
|
178
|
+
|
|
179
|
+
[mqtt.device_discovery.overrides.device]
|
|
180
|
+
|
|
181
|
+
# if not set, serial_number and identifiers default to the UTF8 string representation of 0xF010 (device serial number).
|
|
182
|
+
# in case no identifiers are set and no serial_number is sent by Vitoconnect, no device discovery payload will be published!
|
|
183
|
+
|
|
184
|
+
# identifiers = "any_identifier_defaults_to_serial_number"
|
|
185
|
+
# serial_number = "device_serial_number"
|
|
186
|
+
# name = "Vito"
|
|
187
|
+
# model = "Vito"
|
|
188
|
+
# manufacturer = "Viessmann"
|
|
189
|
+
|
|
190
|
+
# the following override sections will override the default sensor and binary_sensor entity attributes, as listed here:
|
|
191
|
+
# https://www.home-assistant.io/integrations/sensor.mqtt/ and https://www.home-assistant.io/integrations/binary_sensor.mqtt/
|
|
192
|
+
# by default optolink-bridge publishes all data_points as sensors. in case you do not wish to publish a specific data_point,
|
|
193
|
+
# you may set its entry in the overrides section to false, e.g.: some_data_point = false
|
|
194
|
+
[mqtt.device_discovery.overrides.sensor]
|
|
195
|
+
|
|
196
|
+
outside_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1, icon = "mdi:thermometer" }
|
|
197
|
+
averaged_outside_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1, icon = "mdi:thermometer" }
|
|
198
|
+
averaging_time_outside_temperature = { device_class = "duration", unit_of_measurement = "min" }
|
|
199
|
+
|
|
200
|
+
operating_mode = { icon = "mdi:cog", value_template = """
|
|
201
|
+
{% set mapping = ({
|
|
202
|
+
'00': 'Shutdown',
|
|
203
|
+
'01': 'Hot Water Only',
|
|
204
|
+
'02': 'Heating and Hot Water',
|
|
205
|
+
'03': 'Mode 3',
|
|
206
|
+
'04': 'Continuously Reduced',
|
|
207
|
+
'05': 'Continuously Normal',
|
|
208
|
+
'06': 'Normal Shutdown',
|
|
209
|
+
'07': 'Cooling Only'
|
|
210
|
+
}) %}
|
|
211
|
+
{{ mapping[value] | default('Unknown') }}""" }
|
|
212
|
+
|
|
213
|
+
hkl_level = { state_class = "measurement", icon = "mdi:chart-line" }
|
|
214
|
+
hkl_slope = { state_class = "measurement", icon = "mdi:chart-line" }
|
|
215
|
+
hysteresis = { device_class = "temperature", unit_of_measurement = "K", icon = "mdi:thermometer-lines" }
|
|
216
|
+
|
|
217
|
+
buffer_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
218
|
+
primary_circuit_flow_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
219
|
+
secondary_circuit_flow_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
220
|
+
return_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
221
|
+
|
|
222
|
+
"3way_valve_position" = { unit_of_measurement = "%", suggested_display_precision = 0, icon = "mdi:valve", value_template = "{{ value | float * 100 }}" }
|
|
223
|
+
|
|
224
|
+
suction_gas_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
225
|
+
suction_gas_pressure = { device_class = "pressure", unit_of_measurement = "bar", suggested_display_precision = 1 }
|
|
226
|
+
hot_gas_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
227
|
+
hot_gas_pressure = { device_class = "pressure", unit_of_measurement = "bar", suggested_display_precision = 1 }
|
|
228
|
+
liquid_gas_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
229
|
+
condensation_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
230
|
+
evaporation_temperature = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
231
|
+
compressor_power = { unit_of_measurement = "%", suggested_display_precision = 0, icon = "mdi:heat-pump", value_template = "{{ value | int }}" }
|
|
232
|
+
ecv_position = { unit_of_measurement = "%", suggested_display_precision = 0, icon = "mdi:valve", value_template = "{{ value | int }}" }
|
|
233
|
+
|
|
234
|
+
dhw_temperature_storage = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
235
|
+
dhw_temperature_setpoint = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
236
|
+
dhw_temperature_setpoint2 = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
237
|
+
|
|
238
|
+
room_temperature_setpoint_normal = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
239
|
+
room_temperature_setpoint_reduced = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
240
|
+
room_temperature_setpoint_party = { device_class = "temperature", unit_of_measurement = "°C", suggested_display_precision = 1 }
|
|
241
|
+
|
|
242
|
+
compressor_phase = { icon = "mdi:information", value_template = """
|
|
243
|
+
{% set mapping = ({
|
|
244
|
+
'00': 'Off',
|
|
245
|
+
'01': 'Cooling',
|
|
246
|
+
'02': 'Heating',
|
|
247
|
+
'03': 'Error',
|
|
248
|
+
'04': 'Switching to Cooling',
|
|
249
|
+
'05': 'Defrosting',
|
|
250
|
+
'06': 'Waiting',
|
|
251
|
+
'07': 'Standby',
|
|
252
|
+
'08': 'Switching to Heating',
|
|
253
|
+
'09': 'Stopping',
|
|
254
|
+
'0A': 'Manual Operation',
|
|
255
|
+
'0B': 'Starting',
|
|
256
|
+
'0C': 'Utility Lock',
|
|
257
|
+
'0D': 'Pre-Start',
|
|
258
|
+
'0E': 'Post-Stop',
|
|
259
|
+
'0F': 'Blocked',
|
|
260
|
+
'10': 'Pump-Down',
|
|
261
|
+
'11': 'PD -> Comp. start',
|
|
262
|
+
'12': 'PD -> pressure reached',
|
|
263
|
+
'13': 'PD -> shutdown'
|
|
264
|
+
}) %}
|
|
265
|
+
{{ mapping[value[:2]] | default('Unknown') }}""" }
|
|
266
|
+
|
|
267
|
+
compressor_starts = { unit_of_measurement = "cycles", state_class = "total_increasing", icon = "mdi:restart" }
|
|
268
|
+
compressor_operating_hours = { device_class = "duration", unit_of_measurement = "h", state_class = "total_increasing", icon = "mdi:fan-clock" }
|
|
269
|
+
compressor_heating_power = { device_class = "power", unit_of_measurement = "W" }
|
|
270
|
+
compressor_power_consumption = { device_class = "power", unit_of_measurement = "W" }
|
|
271
|
+
|
|
272
|
+
annual_performance_factor = { state_class = "measurement", icon = "mdi:chart-line", value_template = "{{ value | float | round(2) }}" }
|
|
273
|
+
annual_performance_factor_heating = { state_class = "measurement", icon = "mdi:chart-line", value_template = "{{ value | float | round(2) }}" }
|
|
274
|
+
annual_performance_factor_dhw = { state_class = "measurement", icon = "mdi:chart-line", value_template = "{{ value | float | round(2) }}" }
|
|
275
|
+
|
|
276
|
+
energy_balance_factor = { device_class = "power_factor", state_class = "measurement", value_template = "{{ (value | float / 10) | round(2) }}" }
|
|
277
|
+
energy_balance_heating = { device_class = "energy", unit_of_measurement = "kWh", state_class = "total_increasing", icon = "mdi:fire", value_template = "{{ (value | float * states('sensor.energy_balance_factor') | float) | round(2) }}" }
|
|
278
|
+
energy_balance_dhw = { device_class = "energy", unit_of_measurement = "kWh", state_class = "total_increasing", icon = "mdi:water", value_template = "{{ (value | float * states('sensor.energy_balance_factor') | float) | round(2) }}" }
|
|
279
|
+
energy_balance_heating_electric = { device_class = "energy", unit_of_measurement = "kWh", state_class = "total_increasing", icon = "mdi:flash", value_template = "{{ (value | float * states('sensor.energy_balance_factor') | float) | round(2) }}" }
|
|
280
|
+
energy_balance_dhw_electric = { device_class = "energy", unit_of_measurement = "kWh", state_class = "total_increasing", icon = "mdi:flash", value_template = "{{ (value | float * states('sensor.energy_balance_factor') | float) | round(2) }}" }
|
|
281
|
+
|
|
282
|
+
# by default optolink-bridge publishes all data_points as sensors, in case you want to publish specific data_points as
|
|
283
|
+
# binary sensors, you may specify them in the next section. in case you do not want to change any attribute of the
|
|
284
|
+
# binary sensor, you may just specify the data point name with a value of true, e.g.: heating_circuit_circulation_pump = true
|
|
285
|
+
[mqtt.device_discovery.overrides.binary_sensor]
|
|
286
|
+
|
|
287
|
+
heating_circuit_circulation_pump = { payload_on = "01", payload_off = "00", device_class = "running", icon = "mdi:pump" }
|
|
288
|
+
secondary_pump = { payload_on = "01", payload_off = "00", device_class = "running", icon = "mdi:pump" }
|
|
289
|
+
dhw_circulation_pump = { payload_on = "01", payload_off = "00", device_class = "running", icon = "mdi:pump" }
|
|
290
|
+
one_time_dhw = { payload_on = "02", payload_off = "00", device_class = "heat", icon = "mdi:water-thermometer" }
|
|
291
|
+
auxiliary_heater_enable = { payload_on = "01", payload_off = "00", device_class = "running", icon = "mdi:heating-coil" }
|
|
292
|
+
electric_heater_enable = { payload_on = "01", payload_off = "00", device_class = "running", icon = "mdi:heating-coil" }
|
package/discovery.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import packageJson from './package.json' with { type: 'json' };
|
|
2
|
+
import { capitalCase } from 'change-case';
|
|
3
|
+
|
|
4
|
+
export async function publishDevice({
|
|
5
|
+
mqttClient, mqttAvailabilityTopic, mqttDpTopic,
|
|
6
|
+
deviceSerialNo, prefix = 'homeassistant', dps, overrides = {}
|
|
7
|
+
}) {
|
|
8
|
+
if (!deviceSerialNo) {
|
|
9
|
+
throw new TypeError('Device serial number must be provided');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function discoveryComponent(dp) {
|
|
13
|
+
const unique_id = `vito_${deviceSerialNo}_${dp.name}`;
|
|
14
|
+
|
|
15
|
+
// check if there are any overrides for this data point
|
|
16
|
+
let platform = 'sensor', override;
|
|
17
|
+
for (const overridePlatform of Object.keys(overrides)) {
|
|
18
|
+
if (overridePlatform === 'device') { continue; }
|
|
19
|
+
if (override = overrides[overridePlatform]?.[dp.name]) {
|
|
20
|
+
platform = overridePlatform; // the override determines the platform of the data point
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (override === false) {
|
|
26
|
+
return {}; // do not include this data point in device discovery
|
|
27
|
+
} else if (override === true) {
|
|
28
|
+
override = {}; // include this data point with default settings in the specified platform
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
[unique_id]: {
|
|
33
|
+
platform,
|
|
34
|
+
|
|
35
|
+
unique_id,
|
|
36
|
+
name: capitalCase(dp.name), // will automatically get prefixed with the device name
|
|
37
|
+
state_topic: mqttDpTopic(dp),
|
|
38
|
+
|
|
39
|
+
...(override ?? {})
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// build the discovery record
|
|
45
|
+
const discoveryPayload = {
|
|
46
|
+
device: {
|
|
47
|
+
identifiers: deviceSerialNo,
|
|
48
|
+
serial_number: deviceSerialNo,
|
|
49
|
+
name: 'Vito', model: `Vito`,
|
|
50
|
+
manufacturer: 'Viessmann',
|
|
51
|
+
...(overrides?.device ?? {})
|
|
52
|
+
},
|
|
53
|
+
origin: { // see https://www.home-assistant.io/integrations/mqtt/#adding-information-about-the-origin-of-a-discovery-message
|
|
54
|
+
name: 'optolink-bridge',
|
|
55
|
+
sw_version: packageJson.version,
|
|
56
|
+
support_url: 'https://github.com/kristian/optolink-bridge/issues'
|
|
57
|
+
},
|
|
58
|
+
...(mqttAvailabilityTopic ? {
|
|
59
|
+
availability: [ // see https://www.home-assistant.io/integrations/mqtt/#using-availability-topics
|
|
60
|
+
{
|
|
61
|
+
topic: mqttAvailabilityTopic,
|
|
62
|
+
payload_available: 'true',
|
|
63
|
+
payload_not_available: 'false',
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
} : {}),
|
|
67
|
+
components: Object.assign({}, ...[...(dps?.values() ?? [])].map(discoveryComponent))
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// publish to device discovery topic, see: https://www.home-assistant.io/integrations/mqtt/#discovery-messages
|
|
71
|
+
// config messages are retained, see: https://www.home-assistant.io/integrations/mqtt/#using-retained-config-messages
|
|
72
|
+
await mqttClient.publishAsync(`${prefix ?? 'homeassistant'}/device/vito_${deviceSerialNo}/config`,
|
|
73
|
+
JSON.stringify(discoveryPayload), { retain: true });
|
|
74
|
+
}
|
|
Binary file
|
|
Binary file
|
package/docs/logo.png
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|