Skip to content

Commit f35b01a

Browse files
committed
Add support for Home-assistant Energy platform
1 parent bc91b0c commit f35b01a

18 files changed

+515
-7937
lines changed

Docker.entrypoint.sh

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
#!/bin/sh
22
set -e
33

4-
BUNYAN_CLI=''
5-
64
if [ $1 == "node" ] && [ $2 == "index" ] && [ ${LOG_FORMAT} != "json" ]; then
7-
exec "$@" | ./node_modules/.bin/bunyan
5+
exec "$@" | ./node_modules/.bin/bunyan -L -o short
86
else
97
exec "$@"
108
fi

Dockerfile

+5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ ENTRYPOINT ["/usr/bin/entrypoint.sh"]
1515
# Default Command
1616
CMD ["node", "index"]
1717

18+
# Add TZDATA to allow easy local time configuration
19+
RUN apk update \
20+
&& apk add tzdata \
21+
&& rm -rf /var/cache/apk/*
22+
1823
# Copy app
1924
COPY app/ ./
2025

app/config/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module.exports = {
22
emitInterval: process.env.EMIT_INTERVAL || 10,
3+
hassDiscovery: process.env.HASS_DISCOVERY ? process.env.HASS_DISCOVERY.toLowerCase() === 'true' : true,
34
hassDiscoveryPrefix: process.env.HASS_DISCOVERY_PREFIX || 'homeassistant',
45
logLevel: process.env.LOG_LEVEL || 'info',
56
mqttBaseTopic: process.env.MQTT_BASE_TOPIC || 'teleinfo',

app/mqtt/hass.js

+238
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/**
2+
* Home Assistant related stuff.
3+
*/
4+
const log = require('../log');
5+
6+
const {
7+
mqttBaseTopic,
8+
hassDiscoveryPrefix,
9+
} = require('../config');
10+
11+
/**
12+
* Get frame topic.
13+
* @param adco
14+
* @returns {string}
15+
*/
16+
function getFrameTopic(adco) {
17+
return `${mqttBaseTopic}/${adco}`;
18+
}
19+
20+
/**
21+
* Get hass device class.
22+
* @param tag
23+
* @returns {string}
24+
*/
25+
function getDeviceClass(tag) {
26+
let deviceClass;
27+
switch (tag) {
28+
case 'ADPS':
29+
case 'IINST':
30+
case 'IMAX':
31+
case 'ISOUSC':
32+
deviceClass = 'current';
33+
break;
34+
35+
case 'BASE':
36+
case 'BBRHCJB':
37+
case 'BBRHCJR':
38+
case 'BBRHCJW':
39+
case 'BBRHPJB':
40+
case 'BBRHPJR':
41+
case 'BBRHPJW':
42+
case 'EJPHN':
43+
case 'EJPHPM':
44+
case 'HCHC':
45+
case 'HCHP':
46+
deviceClass = 'energy';
47+
break;
48+
49+
case 'PAPP':
50+
deviceClass = 'power';
51+
break;
52+
53+
default:
54+
deviceClass = undefined;
55+
}
56+
return deviceClass;
57+
}
58+
59+
/**
60+
* Get hass state class.
61+
* @param tag
62+
* @returns {string}
63+
*/
64+
function getStateClass(tag) {
65+
let stateClass;
66+
switch (tag) {
67+
case 'BASE':
68+
case 'BBRHCJB':
69+
case 'BBRHCJR':
70+
case 'BBRHCJW':
71+
case 'BBRHPJB':
72+
case 'BBRHPJR':
73+
case 'BBRHPJW':
74+
case 'EJPHN':
75+
case 'EJPHPM':
76+
case 'HCHC':
77+
case 'HCHP':
78+
stateClass = 'measurement';
79+
break;
80+
default:
81+
stateClass = undefined;
82+
}
83+
return stateClass;
84+
}
85+
86+
/**
87+
* Get hass last reset topic.
88+
* @param tag
89+
* @param stateTopic
90+
* @returns {undefined}
91+
*/
92+
function getLastResetTopic(tag, stateTopic) {
93+
let lastResetTopic;
94+
switch (tag) {
95+
case 'BASE':
96+
case 'BBRHCJB':
97+
case 'BBRHCJR':
98+
case 'BBRHCJW':
99+
case 'BBRHPJB':
100+
case 'BBRHPJR':
101+
case 'BBRHPJW':
102+
case 'EJPHN':
103+
case 'EJPHPM':
104+
case 'HCHC':
105+
case 'HCHP':
106+
lastResetTopic = stateTopic;
107+
break;
108+
default:
109+
lastResetTopic = undefined;
110+
}
111+
return lastResetTopic;
112+
}
113+
114+
/**
115+
* Get hass last reset value tempalte.
116+
* @param tag
117+
* @returns {string}
118+
*/
119+
function getLastResetValueTemplate(tag) {
120+
let resetValueTemplate;
121+
switch (tag) {
122+
case 'BASE':
123+
case 'BBRHCJB':
124+
case 'BBRHCJR':
125+
case 'BBRHCJW':
126+
case 'BBRHPJB':
127+
case 'BBRHPJR':
128+
case 'BBRHPJW':
129+
case 'EJPHN':
130+
case 'EJPHPM':
131+
case 'HCHC':
132+
case 'HCHP':
133+
// Indices never reset
134+
resetValueTemplate = '1970-01-01T00:00:00+00:00';
135+
break;
136+
default:
137+
resetValueTemplate = undefined;
138+
}
139+
return resetValueTemplate;
140+
}
141+
142+
/**
143+
* Get hass sensor unit.
144+
* @param tag
145+
* @returns {string}
146+
*/
147+
function getUnit(tag) {
148+
let unit;
149+
switch (tag) {
150+
case 'ADPS':
151+
case 'IINST':
152+
case 'IMAX':
153+
case 'ISOUSC':
154+
unit = 'A';
155+
break;
156+
157+
case 'BASE':
158+
case 'BBRHCJB':
159+
case 'BBRHCJR':
160+
case 'BBRHCJW':
161+
case 'BBRHPJB':
162+
case 'BBRHPJR':
163+
case 'BBRHPJW':
164+
case 'EJPHN':
165+
case 'EJPHPM':
166+
case 'HCHC':
167+
case 'HCHP':
168+
unit = 'Wh';
169+
break;
170+
171+
case 'PAPP':
172+
unit = 'VA';
173+
break;
174+
175+
case 'PEJP':
176+
unit = 'min';
177+
break;
178+
179+
default:
180+
unit = undefined;
181+
}
182+
return unit;
183+
}
184+
185+
/**
186+
* Get hass value template.
187+
* @param tag
188+
* @returns {string}
189+
*/
190+
function getValueTemplate(tag) {
191+
let valueTemplate;
192+
switch (tag) {
193+
case 'ADCO':
194+
valueTemplate = `{{ value_json.${tag}.raw }}`;
195+
break;
196+
default:
197+
valueTemplate = `{{ value_json.${tag}.value }}`;
198+
}
199+
return valueTemplate;
200+
}
201+
202+
/**
203+
* Publish Configuration for home-assistant discovery.
204+
* @param client
205+
* @param adco
206+
* @param frame
207+
*/
208+
async function publishConfigurationForHassDiscovery(client, adco, frame) {
209+
const promises = Object.keys(frame).map(async (tag) => {
210+
const discoveryTopic = `${hassDiscoveryPrefix}/sensor/${mqttBaseTopic}/${adco}_${tag.toLowerCase()}/config`;
211+
log.info(`Publish configuration for tag ${tag} for discovery to topic [${discoveryTopic}]`);
212+
const stateTopic = getFrameTopic(adco);
213+
return client.publish(discoveryTopic, JSON.stringify({
214+
unique_id: `teleinfo_${adco}_${tag}`,
215+
name: `Teleinfo ${adco} ${tag}`,
216+
state_topic: stateTopic,
217+
state_class: getStateClass(tag),
218+
device_class: getDeviceClass(tag),
219+
last_reset_topic: getLastResetTopic(tag, stateTopic),
220+
last_reset_value_template: getLastResetValueTemplate(tag),
221+
value_template: getValueTemplate(tag),
222+
unit_of_measurement: getUnit(tag),
223+
device: {
224+
identifiers: [adco],
225+
manufacturer: 'Enedis',
226+
model: `linky_${adco}`,
227+
name: `Linky ${adco}`,
228+
},
229+
}), {
230+
retain: true,
231+
});
232+
});
233+
return Promise.all(promises);
234+
}
235+
236+
module.exports = {
237+
publishConfigurationForHassDiscovery,
238+
};

0 commit comments

Comments
 (0)