Skip to content

Commit 301d81f

Browse files
committed
override info with device settings
1 parent b2ec683 commit 301d81f

File tree

8 files changed

+164
-102
lines changed

8 files changed

+164
-102
lines changed

.github/workflows/gh-pages.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
with:
3232
node-version: 20
3333
cache: pnpm
34+
cache-dependency-path: './documentation/package-lock.json'
3435

3536
- name: Build Blog
3637
env:

.github/workflows/main.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ jobs:
1515
uses: docker/metadata-action@v5
1616
with:
1717
images: sguernion/rfxcom2mqtt
18+
tags: |
19+
type=raw,value=latest,enable={{is_default_branch}}
1820
1921
- name: Set up QEMU
2022
uses: docker/setup-qemu-action@v2

config.sample.yml

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,45 +47,45 @@ rfxcom:
4747
- remote
4848
- security1
4949

50-
devices:
51-
- id: '0x5C02'
52-
title: 'Bathroom Temp & Hum'
50+
devices:
51+
- id: '0x5C02'
52+
friendlyName: 'Bathroom Temp & Hum'
5353

54-
- id: '0xB9459A'
55-
title: 'Garden motion'
54+
- id: '0xB9459A'
55+
friendlyName: 'Garden motion'
5656

57-
- id: '1001010/1'
58-
name: 'CucuDimmer'
59-
title: 'Kitchen Dimmer Light'
60-
type: 'lighting2'
57+
- id: '1001010/1'
58+
name: 'CucuDimmer'
59+
friendlyName: 'Kitchen Dimmer Light'
60+
type: 'lighting2'
6161

62-
- id: '0x012E00FF'
63-
name: 'Living Room switch'
62+
- id: '0x012E00FF'
63+
friendlyName: 'Living Room switch'
6464

65-
- id: '0x00ED400F'
66-
name: 'Lights'
67-
units:
68-
- unitCode: '1'
69-
name: 'Light1'
70-
title: 'Living Room'
71-
- unitCode: '2'
72-
name: 'Light2'
73-
title: 'Kitchen'
74-
- unitCode: '3'
75-
name: 'Light3'
76-
title: 'Garage'
77-
- unitCode: '4'
78-
name: 'Light4'
79-
title: 'Garden'
80-
type: 'lighting2'
65+
- id: '0x00ED400F'
66+
name: 'Lights'
67+
units:
68+
- unitCode: '1'
69+
name: 'Light1'
70+
friendlyName: 'Living Room'
71+
- unitCode: '2'
72+
name: 'Light2'
73+
friendlyName: 'Kitchen'
74+
- unitCode: '3'
75+
name: 'Light3'
76+
friendlyName: 'Garage'
77+
- unitCode: '4'
78+
name: 'Light4'
79+
friendlyName: 'Garden'
80+
type: 'lighting2'
8181

82-
- id: '0x3D090F'
83-
name: 'Switch1'
84-
command: 'on'
85-
title: 'Living Room Lights on'
86-
type: 'lighting4'
87-
- id: '0x3D090E'
88-
name: 'Switch1'
89-
command: 'off'
90-
title: 'Living Room Lights off'
91-
type: 'lighting4'
82+
- id: '0x3D090F'
83+
name: 'Switch1'
84+
command: 'on'
85+
friendlyName: 'Living Room Lights on'
86+
type: 'lighting4'
87+
- id: '0x3D090E'
88+
name: 'Switch1'
89+
command: 'off'
90+
friendlyName: 'Living Room Lights off'
91+
type: 'lighting4'

documentation/usage/mqtt_topics_and_messages.md

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,43 +38,39 @@ Contains the state of the bridge, this message is published as retained. Payload
3838

3939
Contains information of an device.
4040

41-
Example payload on topic `"rfxcom2mqtt/devices/0x5C02"`:
41+
Example payload on topic `"rfxcom2mqtt/devices/0x01A4F9BE/2"`:
4242
```
43-
{
44-
"title": "Bathroom Temp & Hum",
45-
"type":"temperaturehumidity1",
46-
"subtype": 13,
47-
"id": "0x5C03",
48-
"seqnbr": 12,
49-
"temperature": 18,
50-
"humidity": 74,
51-
"humidityStatus": 3,
52-
"batteryLevel": 9,
53-
"rssi": 6
54-
}
43+
{
44+
"seqnbr": 4,
45+
"subtype": 0,
46+
"id": "0x01A4F9BE",
47+
"unitCode": 2,
48+
"commandNumber": 0,
49+
"command": "Off",
50+
"level": 0,
51+
"rssi": 4,
52+
"type": "lighting2",
53+
"deviceName": [
54+
"KlikAanKlikUit",
55+
"HomeEasy UK",
56+
"Chacon",
57+
"NEXA",
58+
"Intertechno"
59+
],
60+
"subTypeValue": "AC"
61+
}
5562
```
5663

5764
### Publish command examples (topic/payload)
5865

5966
```
60-
rfxcom2mqtt/commmand/CucuDimmer
67+
rfxcom2mqtt/cmd/lighting2/0/0x01A4F9BE/2/set
6168
on
6269
63-
rfxcom2mqtt/commmand/CucuDimmer
70+
rfxcom2mqtt/cmd/lighting2/0/0x01A4F9BE/2/set
6471
off
6572
66-
rfxcom2mqtt/commmand/CucuDimmer
73+
rfxcom2mqtt/cmd/lighting2/0/0x01A4F9BE/2/set
6774
level 15
6875
69-
rfxcom2mqtt/commmand/Switch1 (lighting4, payload identifies device)
70-
on
71-
72-
rfxcom2mqtt/commmand/Switch1
73-
off
74-
75-
rfxcom2mqtt/commmand/Lights/Light1 (lighting2, unitName identifies device)
76-
on
77-
78-
rfxcom2mqtt/commmand/Lights/Light1
79-
off
8076
```

src/libs/Controller.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
import {Settings,read} from './Settings';
2+
import {Settings, SettingDevice, read} from './Settings';
33
import Discovery from './Discovery';
44
import Mqtt from './Mqtt';
55
import Rfxcom, {IRfxcom,MockRfxcom} from './RfxcomBridge';
@@ -25,7 +25,7 @@ export default class Controller implements MqttEventListener{
2525
this.config = read(file);
2626
logger.setLevel(this.config.loglevel);
2727
logger.info("configuration : "+JSON.stringify(this.config));
28-
this.rfxBridge = this.config.mock ? new MockRfxcom() : new Rfxcom(this.config.rfxcom);
28+
this.rfxBridge = this.config.mock ? new MockRfxcom(this.config.rfxcom) : new Rfxcom(this.config.rfxcom);
2929
this.mqttClient = new Mqtt(this.config)
3030
this.discovery = new Discovery( this.mqttClient, this.rfxBridge, this.config );
3131
this.mqttClient.addListener(this.discovery);
@@ -120,7 +120,7 @@ export default class Controller implements MqttEventListener{
120120
let entityName = dn[3];
121121
// Used for units and forms part of the device id
122122
if (dn[4] !== undefined && dn[4].length > 0) {
123-
entityName = entityName + '/' + dn[4];
123+
entityName += '/' + dn[4];
124124
}
125125
this.rfxBridge.onCommand(deviceType, entityName, data.message);
126126
return;
@@ -131,7 +131,7 @@ export default class Controller implements MqttEventListener{
131131
}
132132

133133

134-
sendToMQTT(type: any, evt: any,deviceConf: any) {
134+
sendToMQTT(type: any, evt: any,deviceConf?: SettingDevice) {
135135
logger.info("receive from rfxcom : "+JSON.stringify(evt));
136136
// Add type to event!
137137
evt.type = type;
@@ -145,17 +145,24 @@ export default class Controller implements MqttEventListener{
145145
let topicEntity = deviceId;
146146

147147
// Get device config if available
148-
if (deviceConf instanceof Object) {
149-
if (deviceConf.name !== undefined) {
148+
if (deviceConf?.name !== undefined) {
150149
topicEntity = deviceConf.name;
151-
}
152150
}
153151

154152
const json = JSON.stringify(evt, null, 2);
155153
const payload = JSON.parse(json);
156154

157155
if(payload.unitCode !== undefined && !this.rfxBridge.isGroup(payload)){
158156
topicEntity += '/' + payload.unitCode;
157+
if (deviceConf?.units) {
158+
deviceConf?.units.forEach( unit => {
159+
if(parseInt(unit.unitCode) === parseInt(payload.unitCode)){
160+
if (unit.name !) {
161+
topicEntity = unit.name;
162+
}
163+
}
164+
});
165+
}
159166
}
160167

161168
this.mqttClient.publish(this.mqttClient.topics.devices + '/' + topicEntity, json, (error: any) => {});

src/libs/Discovery.ts

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
var rfxcom = require('rfxcom');
44
import {IRfxcom} from './RfxcomBridge';
5-
import {Settings, SettingHass} from './Settings';
5+
import {Settings, SettingHass, SettingDevice} from './Settings';
66
import Mqtt from './Mqtt';
77
import { DeviceEntity, DeviceBridge,BridgeInfo,MQTTMessage,MqttEventListener } from './models';
88
import utils from './utils';
@@ -92,9 +92,11 @@ export default class Discovery implements MqttEventListener{
9292
export class HomeassistantDiscovery extends AbstractDiscovery{
9393

9494
protected state: State;
95+
protected devicesConfig: SettingDevice[];
9596

9697
constructor(mqtt: Mqtt, rfxtrx: IRfxcom, config : Settings){
9798
super(mqtt, rfxtrx, config);
99+
this.devicesConfig = config.rfxcom.devices;
98100
this.state = new State(config);
99101
}
100102

@@ -133,24 +135,41 @@ export class HomeassistantDiscovery extends AbstractDiscovery{
133135
// get from save state
134136
let entityState = this.state.get({id: entityName,type:deviceType,subtype:data.message.subtype})
135137
this.updateEntityStateFromValue(entityState,value);
136-
this.rfxtrx.sendCommand(deviceType,subTypeValue,entityState.rfxFunction,id+"/"+unitCode);
137-
this.mqtt.publish(this.mqtt.topics.devices + '/' + entityTopic, JSON.stringify(entityState), (error: any) => {},{retain: true, qos: 1});
138+
this.rfxtrx.sendCommand(deviceType,subTypeValue,entityState.rfxFunction,entityName);
139+
this.mqtt.publish(this.mqtt.topics.devices + '/' + entityName, JSON.stringify(entityState), (error: any) => {},{retain: true, qos: 1});
138140
}
139141

140142
updateEntityStateFromValue(entityState: any,value: string){
141-
if( entityState.type === 'lighting1' || entityState.type === 'lighting2' || entityState.type === 'lighting3'
142-
|| entityState.type === 'lighting5' || entityState.type === 'lighting6') {
143-
if (value === "On" || value === "Group On") {
144-
//TODO load value from rfxcom commands
145-
entityState.commandNumber = (value === "Group On")?4:1;
143+
if( entityState.deviceType === 'lighting1' || entityState.deviceType === 'lighting2' || entityState.deviceType === 'lighting3'
144+
|| entityState.deviceType === 'lighting5' || entityState.deviceType === 'lighting6' ) {
145+
const cmd = value.toLowerCase().split(" ")
146+
let command = cmd[0];
147+
if (cmd[0] === "group") {
148+
command = cmd[1];
149+
150+
}
151+
if (command === "on") {
152+
entityState.commandNumber = (cmd[0] === "group")?4:1; //WORK only for lithing2
146153
entityState.rfxFunction = 'switchOn';
147-
} else {
148-
entityState.commandNumber = (value === "Group On")?3:0;
149-
entityState.rfxFunction = 'switchOff';
154+
} else if (command === "off") {
155+
entityState.rfxFunction = (cmd[0] === "group")?3:0; //WORK only for lithing2
156+
entityState.rfxCommand = 'switchOff';
157+
}else{
158+
if (cmd[0] === "level") {
159+
entityState.rfxFunction = 'setLevel';
160+
entityState.rfxOpt = cmd[1];
161+
}
150162
}
151-
entityState.command = value;
163+
}else if (entityState.deviceType === "lighting4") {
164+
entityState.rfxFunction = 'sendData';
165+
}else if (entityState.deviceType === "chime1") {
166+
entityState.rfxFunction = 'chime';
167+
} else {
168+
logger.error('device type ('+entityState.deviceType+') not supported');
152169
}
153170

171+
172+
154173
//TODO get command for other deviceType
155174
}
156175

@@ -160,19 +179,42 @@ export class HomeassistantDiscovery extends AbstractDiscovery{
160179
const devicePrefix = this.config.discovery_device;
161180
let id = payload.id;
162181
let deviceId = payload.subTypeValue+"_"+id.replace("0x","");
182+
let deviceTopic = payload.id
183+
let deviceName = deviceId;
163184
let entityId = payload.subTypeValue+"_"+id.replace("0x","");
164-
let entityTopic = payload.id;
165185
let entityName = payload.id;
166-
186+
let entityTopic = payload.id
187+
188+
const deviceConf = this.devicesConfig.find((dev: any) => dev.id === id);
189+
190+
if (deviceConf?.name !== undefined) {
191+
entityTopic = deviceConf.name;
192+
deviceTopic = deviceConf.name;
193+
}
194+
195+
167196
if(payload.unitCode !== undefined && !this.rfxtrx.isGroup(payload)){
168197
entityId += '_' + payload.unitCode;
169198
entityTopic += '/'+ payload.unitCode;
170199
entityName += '_'+payload.unitCode;
200+
if (deviceConf?.units) {
201+
deviceConf?.units.forEach( unit => {
202+
if(parseInt(unit.unitCode) === parseInt(payload.unitCode)){
203+
if (unit.name !) {
204+
entityTopic = unit.name;
205+
}
206+
}
207+
});
208+
}
171209
}
172210

173211
this.state.set({id: entityName,type:payload.type,subtype:payload.subtype},payload,"event");
174212

175-
const deviceJson = new DeviceEntity([devicePrefix+'_'+deviceId],deviceId);
213+
if (deviceConf?.friendlyName) {
214+
deviceName = deviceConf?.friendlyName;
215+
}
216+
217+
const deviceJson = new DeviceEntity([devicePrefix+'_'+deviceId,devicePrefix+'_'+deviceName],deviceName);
176218

177219
if( payload.rssi !== undefined ){
178220
const json = {
@@ -182,16 +224,16 @@ export class HomeassistantDiscovery extends AbstractDiscovery{
182224
entity_category: "diagnostic",
183225
icon: "mdi:signal",
184226
json_attributes_topic: this.topicDevice + '/' + entityTopic,
185-
name: deviceId+" Linkquality",
186-
object_id: deviceId+'_linkquality',
227+
name: deviceName+" Linkquality",
228+
object_id: deviceTopic+'_linkquality',
187229
origin: this.discoveryOrigin,
188230
state_class: "measurement",
189231
state_topic: this.topicDevice + '/' + entityTopic,
190-
unique_id: deviceId +'_linkquality_' + devicePrefix,
232+
unique_id: deviceTopic +'_linkquality_' + devicePrefix,
191233
unit_of_measurement:"dBm",
192234
value_template: "{{ value_json.rssi }}"
193235
};
194-
this.publishDiscovery('sensor/' + deviceId +'/linkquality/config',JSON.stringify(json));
236+
this.publishDiscovery('sensor/' + deviceTopic +'/linkquality/config',JSON.stringify(json));
195237
}
196238
if( payload.type === 'lighting1' || payload.type === 'lighting2' || payload.type === 'lighting3'
197239
|| payload.type === 'lighting5' || payload.type === 'lighting6' ){
@@ -221,7 +263,7 @@ export class HomeassistantDiscovery extends AbstractDiscovery{
221263
unique_id: entityId+'_'+devicePrefix,
222264
value_template:"{{ value_json.command }}"
223265
};
224-
this.publishDiscovery('switch/' + entityId +'/config',JSON.stringify(json));
266+
this.publishDiscovery('switch/' + entityTopic +'/config',JSON.stringify(json));
225267
}
226268

227269
}

0 commit comments

Comments
 (0)