Skip to content

Commit

Permalink
v6.0.16
Browse files Browse the repository at this point in the history
  • Loading branch information
seydx committed Sep 21, 2021
1 parent 210a591 commit da10422
Show file tree
Hide file tree
Showing 13 changed files with 225 additions and 11 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

# v6.0.16 - 2021-09-21

## Notable Changes
- **Presence**
- Guest Wifi Presence: Occupancy/Motion sensor which will be triggered if someone is connected to the guest wifi (master device)

## Bugfixes
- Fixed an issue where number lookup didnt work properly (callmonitor)
- Fixed an issue where turning on the deflection affected only the first deflection in the list
- Minor Bugfixes

# v6.0.15 - 2021-09-19

## Other Changes
Expand Down
23 changes: 20 additions & 3 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,11 @@
"description": "Exposes Anyone Sensor to Apple Home.",
"type": "boolean"
},
"guest": {
"title": "Guest Sensor",
"description": "Exposes Guest Sensor to Apple Home.",
"type": "boolean"
},
"accType": {
"title": "Accessory Type",
"type": "string",
Expand All @@ -1246,7 +1251,7 @@
"enum": ["motion"]
}
],
"description": "The accessory type of the anyone sensor."
"description": "The accessory type of the anyone/guest sensor."
}
}
},
Expand Down Expand Up @@ -1351,6 +1356,16 @@
"title": "Anyone Not Detected",
"type": "string",
"description": "Message if nobody detected."
},
"guest_in": {
"title": "Guest Detected",
"type": "string",
"description": "Message if someone connected to guest wlan."
},
"guest_out": {
"title": "Guest Not Detected",
"type": "string",
"description": "Message if no one connected to guest wlan."
}
}
},
Expand Down Expand Up @@ -1847,7 +1862,7 @@
"expandable": true,
"expanded": false,
"orderable": false,
"items": ["options.presence.anyone", "options.presence.accType"]
"items": ["options.presence.anyone", "options.presence.guest", "options.presence.accType"]
},
{
"key": "options",
Expand Down Expand Up @@ -1912,7 +1927,9 @@
"telegram.messages.presence.user_in",
"telegram.messages.presence.user_out",
"telegram.messages.presence.anyone_in",
"telegram.messages.presence.anyone_out"
"telegram.messages.presence.anyone_out",
"telegram.messages.presence.guest_in",
"telegram.messages.presence.guest_out"
]
},
{
Expand Down
5 changes: 4 additions & 1 deletion example/example-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@
},
"presence": {
"anyone": true,
"guest": true,
"accType": "occupancy"
},
"reboot": {
Expand All @@ -295,7 +296,9 @@
"user_in": "Welcome at home @",
"user_out": "Bye Bye @",
"anyone_in": "Someone is at home!",
"anyone_out": "Nobody at home!"
"anyone_out": "Nobody at home!",
"guest_in": "Someone is at home!",
"guest_out": "Nobody at home!"
},
"callmonitor": {
"incoming": "Incoming call from @",
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "homebridge-fritz-platform",
"version": "6.0.15",
"version": "6.0.16",
"description": "Homebridge Plugin to control FritzBox router, smarthome devices and more.",
"main": "index.js",
"funding": [
Expand Down
8 changes: 7 additions & 1 deletion src/accessories/presence/motion/motion.accessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const moment = require('moment');
const logger = require('../../../utils/logger');
const Handler = require('../presence.handler');
const GuestHandler = require('../presence_guest.handler');

const timeout = (ms) => new Promise((res) => setTimeout(res, ms));

Expand All @@ -13,7 +14,12 @@ class Accessory {
this.accessories = accessories;
this.HistoryService = HistoryService;

this.handler = Handler.configure(api, accessories, accessory.context.config.polling, meshMaster);
if (accessory.displayName === 'Guest') {
this.handler = GuestHandler.configure(api, accessories, accessory.context.config.polling, meshMaster);
} else {
this.handler = Handler.configure(api, accessories, accessory.context.config.polling, meshMaster);
}

this.getService();
}

Expand Down
8 changes: 7 additions & 1 deletion src/accessories/presence/occupancy/occupancy.accessory.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

const logger = require('../../../utils/logger');
const Handler = require('../presence.handler');
const GuestHandler = require('../presence_guest.handler');

class Accessory {
constructor(api, accessory, accessories, meshMaster) {
this.api = api;
this.accessory = accessory;

this.handler = Handler.configure(api, accessories, accessory.context.config.polling, meshMaster);
if (accessory.displayName === 'Guest') {
this.handler = GuestHandler.configure(api, accessories, accessory.context.config.polling, meshMaster);
} else {
this.handler = Handler.configure(api, accessories, accessory.context.config.polling, meshMaster);
}

this.getService();
}

Expand Down
12 changes: 10 additions & 2 deletions src/accessories/presence/presence.handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ class Handler {

if (accessory.displayName === 'Anyone') {
const states = this.accessories
.filter((accessory) => accessory.context.config.type === 'presence' && accessory.displayName !== 'Anyone')
.filter(
(accessory) =>
accessory.context.config.type === 'presence' &&
accessory.displayName !== 'Anyone' &&
accessory.displayName !== 'Guest'
)
.map((accessory) => {
const service2 =
accessory.context.config.subtype === 'motion'
Expand Down Expand Up @@ -232,7 +237,10 @@ class Handler {

if (this.hosts.length) {
const userAccessories = this.accessories.filter(
(accessory) => accessory.context.config.type === 'presence' && accessory.displayName !== 'Anyone'
(accessory) =>
accessory.context.config.type === 'presence' &&
accessory.displayName !== 'Anyone' &&
accessory.displayName !== 'Guest'
);

for (const accessory of userAccessories) {
Expand Down
23 changes: 23 additions & 0 deletions src/accessories/presence/presence.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,29 @@ const Setup = (devices, presenceConfig, presenceOptions) => {
devices.set(uuid, anyoneConfig);
}
}

if (presenceOptions.guest) {
const validTypes = ['occupancy', 'motion'];

const guestConfig = {
name: 'Guest',
type: 'presence',
subtype: validTypes.find((el) => el === presenceOptions.accType) || 'occupancy',
accType: validTypes.find((el) => el === presenceOptions.accType) || 'occupancy',
};

const uuid = UUIDgenerate(guestConfig.name);

if (devices.has(uuid)) {
logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
guestConfig.name
);
} else {
logger.debug('New device added!', guestConfig.name);
devices.set(uuid, guestConfig);
}
}
};

module.exports = Setup;
137 changes: 137 additions & 0 deletions src/accessories/presence/presence_guest.handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
'use strict';

const moment = require('moment');
const logger = require('../../utils/logger');
const Telegram = require('../../lib/telegram');

class Handler {
constructor() {
this.hosts = [];
this.configured = false;
}

configure(api, accessories, polling, meshMaster) {
if (this.configured) {
return this;
}

this.api = api;
this.accessories = accessories;
this.polling = polling;
this.wifiUnitGuest = meshMaster.wifiUnits + 1;
this.fritzbox = meshMaster.fritzbox;

this.configured = true;

setTimeout(() => this.poll(), 1000);

return this;
}

// eslint-disable-next-line no-unused-vars
async change(context, accessory, subtype, historyService) {
if (context.oldValue !== context.newValue) {
if (!this.configured) {
logger.debug(
'Handler not configured yet. Skipping CHANGE event.',
`${accessory.displayName} (${accessory.context.config.subtype})`
);
return;
}

subtype = subtype || accessory.context.config.subtype;

if (historyService) {
const lastActivation = moment().unix() - historyService.getInitialTime();

accessory
.getService(this.api.hap.Service.MotionSensor)
.getCharacteristic(this.api.hap.Characteristic.LastActivation)
.updateValue(lastActivation);

historyService.addEntry({ time: moment().unix(), status: context.newValue ? 1 : 0 });
}

let dest = false;

if (context.newValue) {
dest = 'guest_in';

logger.info(
'Someone connected to Guest Wifi',
`${accessory.displayName} (${accessory.context.config.subtype})`
);
} else {
dest = 'guest_out';

logger.info('No one connected to Guest Wifi', `${accessory.displayName} (${accessory.context.config.subtype})`);
}

Telegram.send('presence', dest, false);
}
}

// eslint-disable-next-line no-unused-vars
async get(accessory, subtype, ownCharacteristic) {
if (!this.configured) {
logger.debug(
'Handler not configured yet. Skipping GET event.',
`${accessory.displayName} (${accessory.context.config.subtype})`
);
return accessory.context.config.subtype === 'motion' ? false : 0;
}

// eslint-disable-next-line no-unused-vars
subtype = subtype || accessory.context.config.subtype;

const service =
accessory.context.config.subtype === 'motion'
? this.api.hap.Service.MotionSensor
: this.api.hap.Service.OccupancySensor;

const characteristic =
accessory.context.config.subtype === 'motion'
? this.api.hap.Characteristic.MotionDetected
: this.api.hap.Characteristic.OccupancyDetected;

let state = accessory.getService(service).getCharacteristic(characteristic).value;

const response = await this.fritzbox.exec(
`urn:WLANConfiguration-com:serviceId:WLANConfiguration${this.wifiUnitGuest}`,
'GetTotalAssociations'
);

logger.debug(response, `${accessory.displayName} (${subtype})`);

const connectedToGuestWifi = parseInt(response.NewTotalAssociations);

if (connectedToGuestWifi) {
state = accessory.context.config.subtype === 'motion' ? true : 1;
} else {
state = accessory.context.config.subtype === 'motion' ? false : 0;
}

accessory.getService(service).getCharacteristic(characteristic).updateValue(state);

return state;
}

// eslint-disable-next-line no-unused-vars
async set(state, accessory, subtype, ownCharacteristic) {}

async poll() {
try {
const guestAccessory = this.accessories.find((accessory) => accessory && accessory.displayName === 'Guest');

await this.get(guestAccessory);
} catch (err) {
logger.warn('An error occurred during polling guest device!');
logger.error(err);
} finally {
setTimeout(() => this.poll(), this.polling.timer * 1000);
}
}
}

const handler = new Handler();
module.exports = handler;
1 change: 1 addition & 0 deletions src/accessories/router/router.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const Setup = (devices, routerConfig, extrasConfig, optionsConfig, meshMaster) =
meshMaster.config = device;
meshMaster.configured = true;
meshMaster.fritzbox = device.fritzbox;
meshMaster.wifiUnits = device.wifiUnits;

delete meshMaster.config.fritzbox;
}
Expand Down
3 changes: 2 additions & 1 deletion src/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ function FritzPlatform(log, config, api) {
configured: false,
cityPrefix: this.config.callmonitor.cityPrefix || false,
countryPrefix: this.config.callmonitor.countryPrefix || false,
wifiUnits: 2,
fritzbox: null,
};

Expand All @@ -92,7 +93,7 @@ function FritzPlatform(log, config, api) {
SHSetup(this.devices, this.config.smarthome);
}

if (this.config.presence) {
if (this.config.presence || this.config.options.presence.guest) {
PresenceSetup(this.devices, this.config.presence, this.config.options.presence);
}

Expand Down
1 change: 1 addition & 0 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ exports.generateConfig = (config) => {
},
presence: {
anyone: config.options && config.options.presence && config.options.presence.anyone ? true : false,
guest: config.options && config.options.presence && config.options.presence.guest ? true : false,
accType:
config.options && config.options.presence && config.options.presence.accType
? config.options.presence.accType
Expand Down

0 comments on commit da10422

Please sign in to comment.