Skip to content

Instantly share code, notes, and snippets.

@jeremiehuchet
Last active August 23, 2024 16:41
Show Gist options
  • Select an option

  • Save jeremiehuchet/84e8dc96573e37200c2ab3bd4e013729 to your computer and use it in GitHub Desktop.

Select an option

Save jeremiehuchet/84e8dc96573e37200c2ab3bd4e013729 to your computer and use it in GitHub Desktop.
Shelly modules MQTT announcement for Home-Assistant
function normalizeMac(originalMac) {
let mac = '';
for (let i = 0; i < originalMac.length; i = i + 2) {
mac += originalMac.substring(i, i + 2)
if (i < originalMac.length) {
mac += ':'
}
}
return mac;
}
const info = Shelly.getDeviceInfo();
const mqtt = Shelly.getComponentConfig("mqtt");
const baseConfig = {
'~': mqtt.topic_prefix,
origin: {
name: 'shelly-ha-mqtt-auto-discovery',
sw_version: '0.1',
support_url: 'https://gist.github.com/jeremiehuchet/84e8dc96573e37200c2ab3bd4e013729',
},
device: {
configuration_url: 'http://' + mqtt.client_id,
connections: [
['mac', normalizeMac(info.mac)]
],
hw_version: info.gen,
identifiers: [
info.id
],
manufacturer: 'Shelly',
model: info.model,
name: info.name,
sw_version: info.fw_id
},
availability: [
{
topic: '~/online',
payload_available: 'true',
payload_not_available: 'false',
}
],
};
const coverConfig = Object.assign({
command_topic: '~/rpc',
device_class: 'shutter',
name: 'Cover',
payload_close: JSON.stringify({
id: 0,
src: mqtt.topic_prefix,
method: 'Cover.Close',
params: {
id: 0,
},
}),
payload_open: JSON.stringify({
id: 0,
src: mqtt.topic_prefix,
method: 'Cover.Open',
params: {
id: 0,
},
}),
payload_stop: JSON.stringify({
id: 0,
src: mqtt.topic_prefix,
method: 'Cover.Stop',
params: {
id: 0,
},
}),
position_closed: 0,
position_open: 100,
position_template: '{{ value_json.current_pos | int }}',
position_topic: '~/status/cover:0',
retain: true,
set_position_template: JSON.stringify({
id: 0,
src: mqtt.topic_prefix,
method: 'Cover.GoToPosition',
params: {
id: 0,
pos: '{{ position }}',
},
}),
set_position_topic: '~/rpc',
state_closed: 'closed',
state_closing: 'closing',
state_open: 'open',
state_opening: 'opening',
state_stopped: 'stopped',
state_topic: '~/status/cover:0',
unique_id: info.id,
value_template: '{{ value_json.state }}',
}, baseConfig);
const deviceTempConfig = Object.assign({
device_class: 'temperature',
name: 'Device temperature',
entity_category: 'diagnostic',
icon: 'mdi:thermometer',
unique_id: info.id + '_device_temp',
state_class: 'measurement',
state_topic: '~/status/cover:0',
value_template: '{{ value_json.temperature.tC }}',
unit_of_measurement: '°C',
}, baseConfig);
const restartRequiredConfig = Object.assign({
name: 'Restart required',
icon: 'mdi:power-standby',
entity_category: 'diagnostic',
unique_id: info.id + '_restart_required',
state_class: 'measurement',
state_topic: '~/status/sys',
value_template: '{{ value_json.restart_required }}',
payload_on: true,
payload_off: false,
}, baseConfig);
const lastRestartConfig = Object.assign({
name: 'Last restart',
entity_category: 'diagnostic',
unique_id: info.id + '_last_restart',
state_class: 'measurement',
state_topic: '~/status/sys',
value_template: '{{ ( as_timestamp(now()) - value_json.uptime ) | timestamp_local }}',
}, baseConfig);
const wifiSignalStrengthConfig = Object.assign({
entity_category: 'diagnostic',
device_class: 'timestamp',
state_topic: '~/status/wifi',
device_class: 'signal_strength',
name: 'Wifi signal strength',
unique_id: info.id + '_wifi_rssi',
state_class: 'measurement',
value_template: '{{ value_json.rssi }}',
unit_of_measurement: 'dBm',
}, baseConfig);
const wifiSsidConfig = Object.assign({
entity_category: 'diagnostic',
state_topic: '~/status/wifi',
name: 'Wifi SSID',
unique_id: info.id + '_wifi_ssid',
icon: 'mdi:wifi-settings',
value_template: '{{ value_json.ssid }}',
}, baseConfig);
const wifiIpConfig = Object.assign({
entity_category: 'diagnostic',
state_topic: '~/status/wifi',
name: 'Wifi IP address',
unique_id: info.id + '_wifi_ip',
icon: 'mdi:ip-outline',
value_template: '{{ value_json.sta_ip }}',
}, baseConfig);
const apowerConfig = Object.assign({
entity_category: 'diagnostic',
device_class: 'power',
state_class: 'measurement',
state_topic: '~/status/cover:0',
name: 'Power',
unique_id: info.id + '_apower',
value_template: '{{ value_json.apower }}',
unit_of_measurement: 'W',
suggested_display_precision: 1,
}, baseConfig);
const voltageConfig = Object.assign({
entity_category: 'diagnostic',
device_class: 'voltage',
state_class: 'measurement',
state_topic: '~/status/cover:0',
name: 'Voltage',
unique_id: info.id + '_voltage',
value_template: '{{ value_json.voltage }}',
unit_of_measurement: 'V',
suggested_display_precision: 1,
}, baseConfig);
const currentConfig = Object.assign({
entity_category: 'diagnostic',
device_class: 'current',
state_class: 'measurement',
state_topic: '~/status/cover:0',
name: 'Current',
unique_id: info.id + '_current',
value_template: '{{ value_json.current }}',
unit_of_measurement: 'A',
suggested_display_precision: 1,
}, baseConfig);
const frequencyConfig = Object.assign({
entity_category: 'diagnostic',
device_class: 'frequency',
state_class: 'measurement',
state_topic: '~/status/cover:0',
name: 'Frequency',
unique_id: info.id + '_frequency',
value_template: '{{ value_json.freq }}',
unit_of_measurement: 'Hz',
}, baseConfig);
const aenergyConfig = Object.assign({
entity_category: 'diagnostic',
device_class: 'energy',
state_class: 'total_increasing',
state_topic: '~/status/cover:0',
name: 'Energy',
unique_id: info.id + '_aenergy',
value_template: '{{ value_json.aenergy.total }}',
unit_of_measurement: 'Wh',
suggested_display_precision: 1,
}, baseConfig);
const powerFactorConfig = Object.assign({
entity_category: 'diagnostic',
device_class: 'power_factor',
state_class: 'measurement',
state_topic: '~/status/cover:0',
name: 'Energy',
unique_id: info.id + '_power_factor',
value_template: '{{ value_json.pf * 100 }}',
unit_of_measurement: '%',
suggested_display_precision: 0,
}, baseConfig);
function publish(topic, discoveryPayload) {
MQTT.publish(topic, JSON.stringify(discoveryPayload));
//console.log('HA MQTT auto-discovery published on ' + topic, discoveryPayload);
}
function announce() {
publish('homeassistant/cover/' + info.id + '/config', coverConfig);
publish('homeassistant/sensor/' + info.id + '_device_temp/config', deviceTempConfig);
publish('homeassistant/binary_sensor/' + info.id + '_restart_required/config', restartRequiredConfig);
publish('homeassistant/sensor/' + info.id + '_wifi_rssi/config', wifiSignalStrengthConfig);
publish('homeassistant/sensor/' + info.id + '_wifi_ssid/config', wifiSsidConfig);
publish('homeassistant/sensor/' + info.id + '_wifi_ip/config', wifiIpConfig);
publish('homeassistant/sensor/' + info.id + '_last_restart/config', lastRestartConfig);
publish('homeassistant/sensor/' + info.id + '_apower/config', apowerConfig);
publish('homeassistant/sensor/' + info.id + '_voltage/config', voltageConfig);
publish('homeassistant/sensor/' + info.id + '_current/config', currentConfig);
publish('homeassistant/sensor/' + info.id + '_frequency/config', frequencyConfig);
publish('homeassistant/sensor/' + info.id + '_aenergy/config', aenergyConfig);
publish('homeassistant/sensor/' + info.id + '_power_factor/config', powerFactorConfig);
}
function listenHomeAssistantStatusUpdates() {
if (MQTT.isConnected()) {
console.log('Subscribing to HomeAssistant status');
MQTT.subscribe('homeassistant/status', function(topic, payload) {
console.log('HomeAssistant is ' + payload);
if (payload.toLowerCase() === 'online') {
announce();
}
});
} else {
console.log('Waiting one more second for MQTT connection');
Timer.set(1000, false, listenHomeAssistantStatusUpdates);
}
}
MQTT.setDisconnectHandler(function() {
console.log('MQTT connection lost');
listenHomeAssistantStatusUpdates();
});
announce();
listenHomeAssistantStatusUpdates();
// 20 * 60 * 60 * 1000 + 20 * 60 * 1000
const every_twenty_hours_and_twenty_minutes = 72000000;
Timer.set(every_twenty_hours_and_twenty_minutes, true, announce);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment