Skip to content

Commit

Permalink
Additional system sensors (#52)
Browse files Browse the repository at this point in the history
* Use system messages

* error correction

* Update system name source and add phone line sensor

* Update battery and phoneline payloads

* Update battery and phone line payloads

* Update logic

* Reorder discovery

* Reorder discovery

* Update phone line logic

* 2 more binary sensors, system messaging

* Update messaging

* Reduce logging

* Change system messaging

* Change system messaging

* Initialization logic

* Updated documentation
  • Loading branch information
markxroberts authored Aug 14, 2024
1 parent 8760c10 commit ac80147
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 18 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ This project is a fork of [Johann Vanackere](https://github.com/vanackej/risco-m
- Ready status sensor for each partition
- For home arming and group arming, delayed arming introduced in response to partition not ready (otherwise command just fails). This will retry for up to 30 seconds if partition not ready to arm when arming command called. HA alarm control panel will reflect this by showing 'arming'. This is not the same as the Risco 'arming' state which initiates delayed arming (not supported).
- Local alarm code now supported. This doesn't validate with the panel, but is for local validation within Home Assistant. From 20246.4 this is by partition.
- Added binary sensors for system tamper status, phone line status
- System status now pulled directly from system at startup
- ** Breaking change ** Alarm system name now acquired directly from panel unless ```alarm_system_name``` set

## Installation

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@markxroberts/risco-mqtt-local",
"version": "2024.7.0",
"version": "2024.8.0",
"description": "Node Risco Mqtt using local panel API",
"main": "dist/main.js",
"types": "dist/lib/index.d.ts",
Expand Down
5 changes: 5 additions & 0 deletions risco-mqtt-local-addon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
<!-- https://developers.home-assistant.io/docs/add-ons/presentation#keeping-a-changelog -->
## 2023.8.0
- added system binary sensors for phone line, power and tamper status
- system status pulled from panel at startup
- breaking change: alarm system name acquired from system label at startup - this will relabel your sensors.

## To be releases
- add multiple panels support (#TODO)

Expand Down
2 changes: 1 addition & 1 deletion risco-mqtt-local-addon/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
FROM markxroberts/risco-mqtt-local:2024.7.0
FROM markxroberts/risco-mqtt-local:2024.8.0
ENV RISCO_MQTT_HA_CONFIG_FILE="/config/risco-mqtt.json"
2 changes: 1 addition & 1 deletion risco-mqtt-local-addon/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Risco local MQTT
version: 2024.7.0
version: 2024.8.0
slug: risco-mqtt-local-addon
description: Risco alarm HA integration using local TCP communication and MQTT
url: https://ghcr.io/markxroberts/risco-mqtt-local
Expand Down
136 changes: 121 additions & 15 deletions src/lib/risco-mqtt-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Zone,
ZoneList,
PanelOptions,
MBSystem
} from '@markxroberts/risco-lan-bridge/dist';
import pkg from 'winston';
import { cloneDeep } from 'lodash';
Expand Down Expand Up @@ -112,7 +113,7 @@ const CONFIG_DEFAULTS: RiscoMQTTConfig = {
logColorize: false,
ha_discovery_prefix_topic: 'homeassistant',
risco_mqtt_topic: 'risco-alarm-panel',
alarm_system_name: 'Risco Alarm',
alarm_system_name: '',
filter_bypass_zones: true,
ha_state_publishing_delay: 30,
panel: {
Expand Down Expand Up @@ -229,6 +230,7 @@ export function riscoMqttHomeAssistant(userConfig: RiscoMQTTConfig) {
let partitionDetailType;
let partitionReadyStatus = [];
let armingTimer = false
let firstSystemStatus = true

if (!config.mqtt?.url) throw new Error('[RML] MQTT url option is required');

Expand Down Expand Up @@ -569,14 +571,39 @@ export function riscoMqttHomeAssistant(userConfig: RiscoMQTTConfig) {
}
}

function publishSystemStateChange(message) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systemmessage`, `${message}`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system message ${message}`);
function publishSystemStateChange(system: MBSystem) {
if (system.Status !== undefined) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systemmessage`, `${system.Status}`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system message ${system.Status}`);
}
if (system.Status === undefined && firstSystemStatus) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systemmessage`, `System initialized`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system message System initialized`);
} else {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systemmessage`, `No system message`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system message No system message`);
}
firstSystemStatus = false
}

function publishSystemBatteryStatus(message) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systembattery`, `${message}`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system battery state ${message}`);
function publishSystemBatteryStatus(system: MBSystem) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systembattery`, `${system.LowBatteryTrouble}`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system battery state ${system.LowBatteryTrouble}`);
}

function publishSystemPhoneLineStatus(system: MBSystem) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systemphoneline`, `${system.PhoneLineTrouble}`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system phone line state ${system.PhoneLineTrouble}`);
}

function publishSystemACPowerStatus(system: MBSystem) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systemacpowerstatus`, `${system.ACTrouble}`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system ac power state ${system.ACTrouble}`);
}

function publishSystemTamperStatus(system: MBSystem) {
mqttClient.publish(`${config.risco_mqtt_topic}/alarm/systemtamper`, `${system.BoxTamper}`, { qos: 1, retain: true });
logger.verbose(`[Panel => MQTT] Published system tamper state ${system.BoxTamper}`);
}

function partitionStatus(partition: Partition) {
Expand Down Expand Up @@ -748,6 +775,10 @@ export function riscoMqttHomeAssistant(userConfig: RiscoMQTTConfig) {
}

function getDeviceInfo() {
if (config.alarm_system_name ==='') {
config.alarm_system_name = panel.mbSystem.Label
logger.debug(`[RML] Alarm system name from panel is ${panel.mbSystem.Label}. Setting this as device name`)
}
return {
manufacturer: 'Risco',
model: `${panel.riscoComm.panelInfo.PanelModel}/${panel.riscoComm.panelInfo.PanelType}`,
Expand Down Expand Up @@ -831,8 +862,8 @@ export function riscoMqttHomeAssistant(userConfig: RiscoMQTTConfig) {
availability: [
{topic: `${config.risco_mqtt_topic}/alarm/status`},
{topic: `${config.risco_mqtt_topic}/alarm/button_status`}],
payload_on: 'LowBattery',
payload_off: 'BatteryOk',
payload_on: 'true',
payload_off: 'false',
device_class: 'battery',
device: getDeviceInfo(),
};
Expand All @@ -843,6 +874,69 @@ export function riscoMqttHomeAssistant(userConfig: RiscoMQTTConfig) {
logger.info(`[Panel => MQTT][Discovery] Published System battery sensor, HA name = ${systemBatteryPayload.name}`);
logger.verbose(`[Panel => MQTT][Discovery] System battery sensor payload\n${JSON.stringify(systemBatteryPayload, null, 2)}`);

const systemPhoneLinePayload = {
name: `Phone line status`,
object_id: `${config.risco_mqtt_topic}-system-phoneline`,
state_topic: `${config.risco_mqtt_topic}/alarm/systemphoneline`,
unique_id: `${config.risco_mqtt_topic}-system-phoneline`,
availability_mode: 'all',
availability: [
{topic: `${config.risco_mqtt_topic}/alarm/status`},
{topic: `${config.risco_mqtt_topic}/alarm/button_status`}],
payload_on: 'false',
payload_off: 'true',
device_class: 'connectivity',
device: getDeviceInfo(),
};

mqttClient.publish(`${config.ha_discovery_prefix_topic}/binary_sensor/${config.risco_mqtt_topic}/systemphoneline/config`, JSON.stringify(systemPhoneLinePayload), {
qos: 1, retain: true,
});
logger.info(`[Panel => MQTT][Discovery] Published System battery sensor, HA name = ${systemPhoneLinePayload.name}`);
logger.verbose(`[Panel => MQTT][Discovery] System battery sensor payload\n${JSON.stringify(systemPhoneLinePayload, null, 2)}`);

const systemTamperPayload = {
name: `System tamper`,
object_id: `${config.risco_mqtt_topic}-system-tamper`,
state_topic: `${config.risco_mqtt_topic}/alarm/systemtamper`,
unique_id: `${config.risco_mqtt_topic}-system-tamper`,
availability_mode: 'all',
availability: [
{topic: `${config.risco_mqtt_topic}/alarm/status`},
{topic: `${config.risco_mqtt_topic}/alarm/button_status`}],
payload_on: 'true',
payload_off: 'false',
device_class: 'tamper',
device: getDeviceInfo(),
};

mqttClient.publish(`${config.ha_discovery_prefix_topic}/binary_sensor/${config.risco_mqtt_topic}/systemtamper/config`, JSON.stringify(systemTamperPayload), {
qos: 1, retain: true,
});
logger.info(`[Panel => MQTT][Discovery] Published System tamper sensor, HA name = ${systemTamperPayload.name}`);
logger.verbose(`[Panel => MQTT][Discovery] System tamper sensor payload\n${JSON.stringify(systemTamperPayload, null, 2)}`);

const systemACPowerPayload = {
name: `AC Power status`,
object_id: `${config.risco_mqtt_topic}-system-acpowerstatus`,
state_topic: `${config.risco_mqtt_topic}/alarm/systemacpowerstatus`,
unique_id: `${config.risco_mqtt_topic}-system-acpowerstatus`,
availability_mode: 'all',
availability: [
{topic: `${config.risco_mqtt_topic}/alarm/status`},
{topic: `${config.risco_mqtt_topic}/alarm/button_status`}],
payload_on: 'false',
payload_off: 'true',
device_class: 'power',
device: getDeviceInfo(),
};

mqttClient.publish(`${config.ha_discovery_prefix_topic}/binary_sensor/${config.risco_mqtt_topic}/systemacpowerstatus/config`, JSON.stringify(systemACPowerPayload), {
qos: 1, retain: true,
});
logger.info(`[Panel => MQTT][Discovery] Published System AC power status sensor, HA name = ${systemACPowerPayload.name}`);
logger.verbose(`[Panel => MQTT][Discovery] System AC power status sensor sensor payload\n${JSON.stringify(systemACPowerPayload, null, 2)}`);

const republishStatePayload = {
name: `Republish state payload`,
object_id: `${config.risco_mqtt_topic}-republish-state`,
Expand Down Expand Up @@ -1234,11 +1328,14 @@ export function riscoMqttHomeAssistant(userConfig: RiscoMQTTConfig) {
for (const systemoutput of activeSystemOutputs(panel.outputs)) {
publishOutputStateChange(systemoutput, '0');
}
initialized = true
logger.info(`[RML] Finished publishing initial partitions, zones and output states to Home assistant`);
publishSystemStateChange('System initialized')
publishSystemBatteryStatus(panel.mbSystem)
publishSystemPhoneLineStatus(panel.mbSystem)
publishSystemACPowerStatus(panel.mbSystem)
publishSystemTamperStatus(panel.mbSystem)
publishSystemStateChange(panel.mbSystem)
logger.info(`[RML] Finished publishing initial system, partitions, zones and output states to Home assistant`);
publishPanelStatus(true)
publishSystemBatteryStatus('BatteryOk')


}

Expand Down Expand Up @@ -1302,9 +1399,18 @@ export function riscoMqttHomeAssistant(userConfig: RiscoMQTTConfig) {

function statusListener(EventStr) {
if (['LowBattery', 'BatteryOk'].includes(EventStr)) {
publishSystemBatteryStatus(EventStr);
publishSystemBatteryStatus(panel.mbSystem);
}
if (['ACUnplugged', 'ACPlugged'].includes(EventStr)) {
publishSystemACPowerStatus(panel.mbSystem);
}
if (['BoxTamperOpen', 'BoxTamperClosed'].includes(EventStr)) {
publishSystemTamperStatus(panel.mbSystem);
}
if (['PhoneLineTrouble', 'PhoneLineOk'].includes(EventStr)) {
publishSystemPhoneLineStatus(panel.mbSystem);
} else {
publishSystemStateChange(EventStr)
publishSystemStateChange(panel.mbSystem)
}
}

Expand Down

0 comments on commit ac80147

Please sign in to comment.