Skip to content

Commit

Permalink
Added Mqtt to Sensor and Switch
Browse files Browse the repository at this point in the history
  • Loading branch information
kreso975 committed Sep 14, 2024
1 parent 9a0caa3 commit 84621bb
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 52 deletions.
12 changes: 11 additions & 1 deletion config.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,23 @@
"deviceType": "Sensor",
"deviceID": "65432258",
"deviceName": "Balcony",
"mqttBroker": "mqtt://192.168.1.200",
"mqttBroker": "192.168.1.200",
"mqttPort": "1883",
"mqttTemperature": "qiot/things/Attic/Temperature",
"mqttHumidity": "qiot/things/Attic/Humidity",
"mqttUsername": "testuser",
"mqttPassword": "testuser"
},
{
"deviceType": "Switch",
"deviceID": "wqwe65432258",
"deviceName": "Relay",
"mqttBroker": "192.168.1.200",
"mqttPort": "1883",
"mqttSwitch": "iot/things/StergoTestSwitch/switch1",
"mqttUsername": "testuser",
"mqttPassword": "testuser"
},
{
"deviceType": "Sensor",
"deviceID": "65432258",
Expand Down
8 changes: 7 additions & 1 deletion config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
"required": false
},
"mqttBroker": {
"title": "URL Broker",
"title": "Host Broker",
"description": "",
"type": "string",
"required": false
Expand Down Expand Up @@ -159,6 +159,12 @@
"description": "",
"type": "string",
"required": false
},
"mqttSwitch": {
"title": "MQTT Topic Switch",
"description": "",
"type": "string",
"required": false
}
}
}
Expand Down
48 changes: 25 additions & 23 deletions src/platformSensorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { PlatformAccessory, Service } from 'homebridge';
import type { HttpSensorsAndSwitchesHomebridgePlatform } from './platform.js';

import axios, { AxiosError } from 'axios';
import mqtt from 'mqtt';

import * as mqtt from 'mqtt';


/**
Expand All @@ -15,6 +14,8 @@ export class platformSensors {
public temperatureService!: Service;
public humidityService!: Service;

public mqttClient!: mqtt.MqttClient;

public deviceId: string = '';
public deviceType: string = '';
public deviceName: string = '';
Expand All @@ -34,17 +35,12 @@ export class platformSensors {
public mqttHumidity: string = '';
public mqttUsername: string = '';
public mqttPassword: string = '';
public mqttSubscribeTopics = Array;

public mqttOptions = {};


public currentTemperature: number = 20;
public currentHumidity: number = 50;
public updateInterval = 300000;




constructor(
public readonly platform: HttpSensorsAndSwitchesHomebridgePlatform,
public readonly accessory: PlatformAccessory,
Expand All @@ -71,15 +67,6 @@ export class platformSensors {
this.mqttUsername = accessory.context.device.mqttUsername;
this.mqttPassword = accessory.context.device.mqttPassword;

this.mqttOptions = {
keepalive: 10,
clientId: this.deviceName,
clean: true,
username: 'testuser',
password: 'testuser',
rejectUnauthorized: false,
};

if ( !this.deviceType ) {
return;
}
Expand Down Expand Up @@ -129,12 +116,12 @@ export class platformSensors {
}

// We can now use MQTT
if ( this.mqttBroker ){
if ( this.mqttBroker ) {
this.getSensorDataMQTT();
}

// IF we are going with JSON over HTTP
if ( this.sensorUrl ){
if ( this.sensorUrl ) {
this.getSensorData();
setInterval(this.getSensorData.bind(this), this.updateInterval);
}
Expand Down Expand Up @@ -184,27 +171,42 @@ export class platformSensors {
callback(null, this.currentHumidity);
}


//
// Connect to MQTT and update Temperature and Humidity
getSensorDataMQTT() {
const mqttSubscribedTopics: string | string[] | mqtt.ISubscriptionMap = [];

const mqttOptions = {
keepalive: 10,
host: this.mqttBroker,
port: Number(this.mqttPort),
clientId: this.deviceName,
clean: true,
username: this.mqttUsername,
password: this.mqttPassword,
rejectUnauthorized: false,
};

if (this.mqttTemperature) {
//this.mqttSubscribeTopics(this.mqttTemperature);
mqttSubscribedTopics.push(this.mqttTemperature);
}
if (this.mqttHumidity) {
//this.mqttSubscribeTopics(this.mqttHumidity);
mqttSubscribedTopics.push(this.mqttHumidity);
}

const client = mqtt.connect( this.mqttBroker, this.mqttOptions);
const client = mqtt.connect( mqttOptions);
client.on('connect', () => {

this.platform.log(this.deviceName,': MQTT Connected');

client.subscribe(mqttSubscribedTopics, (err) => {
if (!err) {
this.platform.log(this.deviceName,': Subscribed to: ', mqttSubscribedTopics.toString());
} else {
// Need to insert error handler
this.platform.log(err.toString());
}
// Need to insert error handler
});
});

Expand Down
157 changes: 130 additions & 27 deletions src/platformSwitchServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CharacteristicSetCallback, CharacteristicValue, PlatformAccessory, Serv
import type { HttpSensorsAndSwitchesHomebridgePlatform } from './platform.js';

import axios, { AxiosError } from 'axios';
import * as mqtt from 'mqtt';

/**
* Platform Accessory
Expand All @@ -11,6 +12,8 @@ import axios, { AxiosError } from 'axios';
export class platformSwitch {
public service!: Service;

public mqttClient!: mqtt.MqttClient;

public deviceId: string = '';
public deviceType: string = '';
public deviceName: string = '';
Expand All @@ -27,10 +30,17 @@ export class platformSwitch {
public statusStateParam: string = '';
public statusOnCheck: string = '';
public statusOffCheck: string = '';


public mqttBroker: string = '';
public mqttPort: string = '';
public mqttSwitch: string = '';
public mqttUsername: string = '';
public mqttPassword: string = '';

public switchStates = {
On: false,
};


constructor(
public readonly platform: HttpSensorsAndSwitchesHomebridgePlatform,
Expand All @@ -44,21 +54,27 @@ export class platformSwitch {
this.deviceSerialNumber = this.accessory.context.device.deviceSerialNumber || accessory.UUID;
this.deviceFirmwareVersion = this.accessory.context.device.deviceFirmwareVersion || '0.0';

// From Config
this.urlStatus = this.accessory.context.device.urlStatus;
this.statusStateParam = this.accessory.context.device.stateName;
this.statusOnCheck = this.accessory.context.device.onStatusValue;
this.statusOffCheck = this.accessory.context.device.offStatusValue;

// From Config
this.urlON = this.accessory.context.device.urlON;
this.urlOFF = this.accessory.context.device.urlOFF;

this.mqttBroker = accessory.context.device.mqttBroker;
this.mqttPort = accessory.context.device.mqttPort;
this.mqttSwitch = accessory.context.device.mqttSwitch;
this.mqttUsername = accessory.context.device.mqttUsername;
this.mqttPassword = accessory.context.device.mqttPassword;


if ( !this.deviceType) {
this.platform.log.warn('Ignoring accessory; No deviceType defined.');
return;
}

if ( this.deviceType === 'Switch') {
if ( this.deviceType === 'Switch' && ( this.urlON || this.mqttBroker )) {

// set accessory information
this.accessory.getService(this.platform.Service.AccessoryInformation)!
Expand All @@ -67,30 +83,45 @@ export class platformSwitch {
.setCharacteristic(this.platform.Characteristic.FirmwareRevision, this.deviceFirmwareVersion)
.setCharacteristic(this.platform.Characteristic.SerialNumber, this.deviceSerialNumber);

// get the Switch service if it exists, otherwise create a new Switch service
this.service = this.accessory.getService(this.platform.Service.Switch) || this.accessory.addService(this.platform.Service.Switch);

// set the service name, this is what is displayed as the default name on the Home app
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.deviceName);

// each service must implement at-minimum the "required characteristics" for the given service type
// see https://developers.homebridge.io/#/service/Lightbulb

// Try to fetch init power Status of device and check the status every 5 sec
// We are checking status because if it's manualy changed/switched Homekit is not notified
// If we do not have urlStatus defined in config we will skip reading Switch status
if ( this.urlStatus ) {
this.getOn();
setInterval(this.getOn.bind(this), 5000);

if ( this.urlON || this.mqttBroker ) {
// get the Switch service if it exists, otherwise create a new Switch service
this.service = this.accessory.getService(this.platform.Service.Switch) || this.accessory.addService(this.platform.Service.Switch);

// set the service name, this is what is displayed as the default name on the Home app
// in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method.
this.service.setCharacteristic(this.platform.Characteristic.Name, accessory.context.device.deviceName);

// each service must implement at-minimum the "required characteristics" for the given service type
// see https://developers.homebridge.io/#/service/Lightbulb

// Try to fetch init power Status of device and check the status every 5 sec
// We are checking status because if it's manualy changed/switched Homekit is not notified
// If we do not have urlStatus defined in config we will skip reading Switch status

if ( this.urlStatus ) {
this.getOn();
setInterval(this.getOn.bind(this), 5000);
}

if ( this.urlON ) {
// register handlers for the On/Off Characteristic
this.service.getCharacteristic(this.platform.Characteristic.On)
.on('set', this.setOn.bind(this))
.on('get', (callback) => {
callback(null, this.switchStates.On);
});
}

// We can now use MQTT
if ( this.mqttBroker ) {
this.initMQTT();

this.service.getCharacteristic(this.platform.Characteristic.On)
.on('set', this.publishMQTTmessage.bind(this));

}
}

// register handlers for the On/Off Characteristic
this.service.getCharacteristic(this.platform.Characteristic.On)
.on('set', this.setOn.bind(this))
.on('get', (callback) => {
callback(null, this.switchStates.On);
});
}
}

Expand Down Expand Up @@ -187,4 +218,76 @@ export class platformSwitch {

}
}

getStatus(isOn: boolean): string {
return isOn ? 'ON' : 'OFF';
}
//
// Connect to MQTT and update Switches
initMQTT() {
const mqttSubscribedTopics: string | string[] | mqtt.ISubscriptionMap = [];

const mqttOptions = {
keepalive: 10,
host: this.mqttBroker,
port: Number(this.mqttPort),
clientId: this.deviceName,
clean: true,
username: this.mqttUsername,
password: this.mqttPassword,
rejectUnauthorized: false,
};

if (this.mqttSwitch) {
mqttSubscribedTopics.push( this.mqttSwitch );
}

this.mqttClient = mqtt.connect( mqttOptions );
this.mqttClient.on('connect', () => {

this.platform.log(this.deviceName,': MQTT Connected');

this.mqttClient.subscribe(mqttSubscribedTopics, (err) => {
if (!err) {
this.platform.log(this.deviceName,': Subscribed to: ', mqttSubscribedTopics.toString());
} else {
// Need to insert error handler
this.platform.log(err.toString());
}
});
});

this.mqttClient.on('message', (topic, message) => {
//this.platform.log(`Received message: ${message.toString()}`);
if ( topic === this.mqttSwitch ) {
this.platform.log(this.deviceName,': Status set to: ', this.getStatus(Boolean(message.toString())));

if ( message.toString() === '1' ) {
this.switchStates.On = true;
}
if ( message.toString() === '0' ) {
this.switchStates.On = false;
}

this.service.updateCharacteristic(this.platform.Characteristic.On, this.switchStates.On);
}
});
}

// Function to publish a message
publishMQTTmessage(value: CharacteristicValue, callback: CharacteristicSetCallback): void {

this.platform.log.debug(this.deviceName, ': Setting power state to:', this.getStatus(!this.switchStates.On) );

this.mqttClient.publish(this.mqttSwitch, String(Number(!this.switchStates.On)), { qos: 1, retain: true }, (err) => {
if (err) {
this.platform.log.debug(this.deviceName, ': Failed to publish message:', err);
} else {
this.service.updateCharacteristic(this.platform.Characteristic.On, this.switchStates.On);
this.platform.log.debug(this.deviceName, ': Message published successfully');
}
});

callback(null);
}
}

0 comments on commit 84621bb

Please sign in to comment.