@homebridge-plugins/homebridge-tado
Version:
Homebridge plugin for controlling tado° devices.
994 lines (847 loc) • 35.8 kB
JavaScript
import fs from 'fs-extra';
import Logger from '../helper/logger.js';
import TadoApi from './tado-api.js';
import Telegram from '../helper/telegram.js';
//https://stackoverflow.com/a/15710692
const hashCode = (s) =>
Math.abs(
s.split('').reduce((a, b) => {
a = (a << 5) - a + b.charCodeAt(0);
return a & a;
}, 0)
).toString();
const devices = new Map();
const deviceHandler = new Map();
let telegram;
export default {
add: async function (config, auths, storagePath) {
config.homes = config.homes || [];
for (const auth of auths) {
const tado = new TadoApi('Configuration', auth, storagePath, false);
const me = await tado.getMe();
for (const foundHome of me.homes) {
let homeIndex;
config.homes.forEach((home, index) => {
if (home.name === foundHome.name || home.id === foundHome.id) {
homeIndex = index;
}
});
if (homeIndex === undefined) {
const homeConfig = {
id: foundHome.id,
name: foundHome.name,
username: auth.username,
tadoApiUrl: auth.tadoApiUrl,
skipAuth: auth.skipAuth,
polling: 300,
zones: [],
presence: {
anyone: false,
accTypeAnyone: 'OCCUPANCY',
user: [],
},
weather: {
temperatureSensor: false,
solarIntensity: false,
accTypeSolarIntensity: 'LIGHTBULB'
},
extras: {
centralSwitch: false,
runningInformation: false,
boostSwitch: false,
sheduleSwitch: false,
turnoffSwitch: false,
presenceLock: false,
accTypePresenceLock: 'ALARM',
accTypeChildLock: 'SWITCH',
childLockSwitches: [],
},
telegram: {
active: false,
},
};
//Home Informations
const homeInfo = await tado.getHome(foundHome.id);
homeConfig.temperatureUnit = homeInfo.temperatureUnit;
homeConfig.geolocation = {
longitude: homeInfo.geolocation.longitude.toString(),
latitude: homeInfo.geolocation.latitude.toString(),
};
//Mobile Devices Informations
const mobileDevices = await tado.getMobileDevices(foundHome.id);
homeConfig.presence.user = mobileDevices.map((user) => {
return {
active: false,
name: user.name,
accType: 'OCCUPANCY',
};
});
//Zone Informations
const zones = await tado.getZones(foundHome.id);
for (const zone of zones) {
if (zone.devices)
zone.devices.forEach((device) => {
if (device.deviceType && (device.deviceType.includes('VA01') || device.deviceType.includes('VA02')))
//https://community.tado.com/en-gb/discussion/705/released-child-lock
homeConfig.extras.childLockSwitches.push({
active: false,
name: zone.name + ' ' + device.shortSerialNo,
serialNumber: device.shortSerialNo,
});
});
const capabilities = await tado.getZoneCapabilities(foundHome.id, zone.id);
homeConfig.zones.push({
active: true,
id: zone.id,
name: zone.name,
type: zone.type,
delaySwitch: false,
autoOffDelay: false,
noBattery: false,
mode: 'MANUAL',
modeTimer: 30,
easyMode: false,
minValue: capabilities.temperatures
? homeConfig.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.min
: capabilities.temperatures.fahrenheit.min
: 5,
maxValue: capabilities.temperatures
? homeConfig.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.max
: capabilities.temperatures.fahrenheit.max
: 25,
minStep: capabilities.temperatures
? homeConfig.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.step
: capabilities.temperatures.fahrenheit.step
: 1,
openWindowSensor: false,
openWindowSwitch: false,
accTypeOpenWindowSwitch: 'SWITCH',
separateTemperature: false,
separateHumidity: false,
accTypeBoiler: 'SWITCH',
boilerTempSupport: false,
});
}
config.homes.push(homeConfig);
}
}
}
return config;
},
resync: async function (config, auths, storagePath) {
const availableHomesInApis = [];
for (const auth of auths) {
//Init API with credentials
const tado = new TadoApi('Configuration', {
username: auth.username,
tadoApiUrl: auth.tadoApiUrl,
skipAuth: auth.skipAuth
}, storagePath, false);
const me = await tado.getMe();
me.homes.forEach((foundHome) => {
availableHomesInApis.push({
id: foundHome.id,
name: foundHome.name,
username: auth.username,
tadoApiUrl: auth.tadoApiUrl,
skipAuth: auth.skipAuth
});
});
}
//remove non exist homes from config that doesnt exist in api
for (let [i, home] of config.homes.entries()) {
let foundHome;
for (const apiHome of availableHomesInApis) {
if (home.name === apiHome.name || home.id === apiHome.id) {
foundHome = apiHome;
}
}
if (!foundHome) {
config.homes.splice(i, 1);
}
}
//refresh existing homes
for (let home of config.homes.entries()) {
if (home.name && home.username) {
config = await this.refresh(home.name, config, {
username: home.username,
tadoApiUrl: home.tadoApiUrl,
skipAuth: home.skipAuth
}, storagePath);
}
}
config = await this.add(config, availableHomesInApis, storagePath);
return config;
},
refresh: async function (currentHome, config, auth, storagePath) {
const tado = new TadoApi('Configuration', auth, storagePath, false);
//Home Informations
let home = config.homes.find((home) => home && home.name === currentHome);
if (!home) throw new Error('Cannot refresh ' + currentHome + '. Not found in config!');
if (!home.id) {
const me = await tado.getMe();
me.homes.map((foundHome) => {
if (foundHome.name === home.name) home.id = foundHome.id;
});
if (!home.id)
throw new Error('Cannot get a Home ID for ' + home.name + '. ' + home.name + ' not found for this user!');
}
const homeInfo = await tado.getHome(home.id);
for (let [i, home] of config.homes.entries()) {
if (config.homes[i].name === homeInfo.name) {
config.homes[i].id = homeInfo.id;
config.homes[i].username = auth.username;
config.homes[i].tadoApiUrl = auth.tadoApiUrl;
config.homes[i].skipAuth = auth.skipAuth;
config.homes[i].temperatureUnit = homeInfo.temperatureUnit || 'CELSIUS';
config.homes[i].zones = config.homes[i].zones || [];
if (homeInfo.geolocation)
config.homes[i].geolocation = {
longitude: homeInfo.geolocation.longitude.toString(),
latitude: homeInfo.geolocation.latitude.toString(),
};
//init devices for childLock
config.homes[i].extras = config.homes[i].extras || {};
config.homes[i].extras.childLockSwitches = config.homes[i].extras.childLockSwitches || [];
let allFoundDevices = [];
//Mobile Devices Informations
const mobileDevices = await tado.getMobileDevices(home.id);
if (!config.homes[i].presence)
config.homes[i].presence = {
anyone: false,
accTypeAnyone: 'OCCUPANCY',
user: [],
};
//Remove not registred devices
config.homes[i].presence.user.forEach((user, index) => {
let found = false;
mobileDevices.forEach((foundUser) => {
if (foundUser.name === user.name) {
found = true;
}
});
if (!found) {
config.homes[i].presence.user.splice(index, 1);
}
});
//Check for new registred devices
if (config.homes[i].presence.user.length) {
for (const foundUser of mobileDevices) {
let userIndex;
config.homes[i].presence.user.forEach((user, index) => {
if (user.name === foundUser.name) {
userIndex = index;
}
});
if (userIndex === undefined) {
config.homes[i].presence.user.push({
active: false,
name: foundUser.name,
accType: 'OCCUPANCY',
});
}
}
} else {
config.homes[i].presence.user = mobileDevices.map((user) => {
return {
active: false,
name: user.name,
accType: 'OCCUPANCY',
};
});
}
//Zone Informations
const zones = await tado.getZones(home.id);
//Remove not available zones
config.homes[i].zones.forEach((zone, index) => {
let found = false;
zones.forEach((foundZone) => {
if (foundZone.name === zone.name) {
found = true;
}
});
if (!found) {
config.homes[i].zones.splice(index, 1);
}
});
//Check for new zones or refresh exist one
if (config.homes[i].zones.length) {
for (const foundZone of zones) {
const capabilities = await tado.getZoneCapabilities(home.id, foundZone.id);
if (foundZone.devices)
foundZone.devices.forEach((dev) => {
if (dev.deviceType && (dev.deviceType.includes('VA01') || dev.deviceType.includes('VA02')))
allFoundDevices.push({
name: foundZone.name + ' ' + dev.shortSerialNo,
serialNumber: dev.shortSerialNo,
});
});
let zoneIndex;
config.homes[i].zones.forEach((zone, index) => {
if (zone.name === foundZone.name) {
zoneIndex = index;
}
});
if (zoneIndex !== undefined) {
config.homes[i].zones[zoneIndex].id = foundZone.id;
config.homes[i].zones[zoneIndex].type = foundZone.type;
config.homes[i].zones[zoneIndex].minValue = capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.min
: capabilities.temperatures.fahrenheit.min
: 5;
config.homes[i].zones[zoneIndex].maxValue = capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.max
: capabilities.temperatures.fahrenheit.max
: 25;
config.homes[i].zones[zoneIndex].minStep = capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.step
: capabilities.temperatures.fahrenheit.step
: 1;
} else {
config.homes[i].zones.push({
active: true,
id: foundZone.id,
name: foundZone.name,
type: foundZone.type,
delaySwitch: false,
autoOffDelay: false,
noBattery: false,
mode: 'MANUAL',
modeTimer: 30,
minValue: capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.min
: capabilities.temperatures.fahrenheit.min
: 5,
maxValue: capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.max
: capabilities.temperatures.fahrenheit.max
: 25,
minStep: capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.step
: capabilities.temperatures.fahrenheit.step
: 1,
easyMode: false,
openWindowSensor: false,
openWindowSwitch: false,
accTypeOpenWindowSwitch: 'SWITCH',
separateTemperature: false,
separateHumidity: false,
accTypeBoiler: 'SWITCH',
boilerTempSupport: false,
});
}
}
} else {
for (const zone of zones) {
const capabilities = await tado.getZoneCapabilities(home.id, zone.id);
if (zone.devices)
zone.devices.forEach((dev) => {
if (dev.deviceType && (dev.deviceType.includes('VA01') || dev.deviceType.includes('VA02')))
allFoundDevices.push({
name: zone.name + ' ' + dev.shortSerialNo,
serialNumber: dev.shortSerialNo,
});
});
config.homes[i].zones.push({
active: true,
id: zone.id,
name: zone.name,
type: zone.type,
delaySwitch: false,
autoOffDelay: false,
noBattery: false,
mode: 'MANUAL',
modeTimer: 30,
minValue: capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.min
: capabilities.temperatures.fahrenheit.min
: 5,
maxValue: capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.max
: capabilities.temperatures.fahrenheit.max
: 25,
minStep: capabilities.temperatures
? homeInfo.temperatureUnit === 'CELSIUS'
? capabilities.temperatures.celsius.step
: capabilities.temperatures.fahrenheit.step
: 1,
easyMode: false,
openWindowSensor: false,
openWindowSwitch: false,
accTypeOpenWindowSwitch: 'SWITCH',
separateTemperature: false,
separateHumidity: false,
accTypeBoiler: 'SWITCH',
boilerTempSupport: false,
});
}
}
//remove non existing childLockSwitches
config.homes[i].extras.childLockSwitches.forEach((childLockSwitch, index) => {
let found = false;
allFoundDevices.forEach((foundDevice) => {
if (foundDevice.serialNumber === childLockSwitch.serialNumber) {
found = true;
}
});
if (!found) {
config.homes[i].extras.childLockSwitches.splice(index, 1);
}
});
//check for new childLockSwitches
if (config.homes[i].extras.childLockSwitches.length) {
for (const foundDevice of allFoundDevices) {
let found = false;
config.homes[i].extras.childLockSwitches.forEach((childLockSwitch) => {
if (childLockSwitch.serialNumber === foundDevice.serialNumber) {
found = true;
}
});
if (!found) {
config.homes[i].extras.childLockSwitches.push({
active: false,
name: foundDevice.name,
serialNumber: foundDevice.serialNumber,
});
}
}
} else {
config.homes[i].extras.childLockSwitches = allFoundDevices.map((device) => {
return {
active: false,
name: device.name,
serialNumber: device.serialNumber,
};
});
}
}
}
return config;
},
setup: function (config, UUIDGen, storagePath) {
if (config.homes && config.homes.length) {
config.homes.forEach((home) => {
let error = false;
let activeZones = 0;
if (!home.name) {
Logger.warn('There is no name configured for this home. This home will be skipped.');
error = true;
} else if (!home.username) {
Logger.warn('There is no username configured for this home. This home will be skipped.', home.name);
error = true;
}
if (!error) {
//Base Config
const tado = new TadoApi(home.name, {
username: home.username,
tadoApiUrl: home.tadoApiUrl,
skipAuth: home.skipAuth
}, storagePath, true);
const accessoryConfig = {
homeId: home.id,
homeName: home.name,
username: home.username,
tadoApiUrl: home.tadoApiUrl,
skipAuth: home.skipAuth,
temperatureUnit: home.temperatureUnit || 'CELSIUS',
geolocation: home.geolocation,
tado: tado,
anyone: home.presence && home.presence.anyone,
accTypeAnyone: home.presence && home.presence.accTypeAnyone,
weather: home.weather || {},
extras: home.extras || {},
zones: home.zones ? home.zones.filter((zone) => zone && zone.active) : [],
presence:
home.presence && home.presence.user ? home.presence.user.filter((user) => user && user.active) : [],
childLock:
home.extras && home.extras.childLockSwitches
? home.extras.childLockSwitches.filter((childLockSwitch) => childLockSwitch && childLockSwitch.active)
: [],
polling: Number.isInteger(home.polling) ? (home.polling < 30 ? 30 : home.polling) : 300,
};
if (home.zones && home.zones.length) {
let validOpenWindowSwitches = [];
home.zones.forEach((zone) => {
if (zone.active) {
let valid_boilerTypes = ['SWITCH', 'FAUCET'];
let valid_zoneTypes = ['HEATING', 'HOT_WATER', 'AIR_CONDITIONING'];
let valid_modes = ['MANUAL', 'AUTO', 'TIMER', 'CUSTOM'];
if (!zone.name) {
Logger.warn('There is no name configured for this zone. This zone will be skipped.', home.name);
error = true;
} else if (!valid_zoneTypes.includes(zone.type)) {
Logger.warn(
'There is no or no correct zone type configured for this zone. Setting it to "HEATING".',
zone.name
);
zone.type = 'HEATING';
}
if (!error) {
activeZones += 1;
const name = home.name + ' ' + zone.name + (zone.type === 'HEATING' ? ' Heater' : zone.type === 'AIR_CONDITIONING' ? ' AC' : ' Boiler');
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
name
);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype =
zone.type === 'HEATING'
? zone.easyMode
? 'zone-heatercooler'
: 'zone-thermostat'
: zone.type === 'AIR_CONDITIONING'
? 'zone-heatercooler-ac'
: valid_boilerTypes.includes(zone.accTypeBoiler) && zone.accTypeBoiler === 'FAUCET'
? 'zone-faucet'
: 'zone-switch';
config.subtype = zone.boilerTempSupport ? 'zone-heatercooler-boiler' : config.subtype;
config.zoneId = zone.id;
config.type = zone.type;
config.separateTemperature = zone.separateTemperature;
config.separateHumidity = zone.separateHumidity;
config.minStep = zone.minStep;
config.minValue = zone.minValue;
config.maxValue = zone.maxValue;
config.openWindowSensor = zone.openWindowSensor;
config.openWindowSwitch = zone.openWindowSwitch;
config.noBattery = zone.noBattery;
config.mode = valid_modes.includes(zone.mode) ? zone.mode : 'MANUAL';
config.modeTimer = zone.modeTimer && zone.modeTimer >= 1 ? zone.modeTimer : 1;
config.delaySwitch = zone.delaySwitch;
config.autoOffDelay = zone.autoOffDelay;
config.model = zone.type;
config.serialNumber = hashCode(name);
devices.set(uuid, config);
//Configure openWindowSensor
if (zone.openWindowSensor) {
const thisName = home.name + ' ' + zone.name + ' Window';
const uuid2 = UUIDGen.generate(thisName);
if (devices.has(uuid2)) {
Logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
thisName
);
} else {
let newConfig = { ...config };
newConfig.name = thisName;
newConfig.subtype = 'zone-window-contact';
newConfig.model = newConfig.subtype;
newConfig.serialNumber = hashCode(zone.name);
devices.set(uuid2, newConfig);
}
}
//Configure openWindowSwitch
if (zone.openWindowSwitch) {
validOpenWindowSwitches.push({
name: zone.name + ' Window',
zoneId: zone.id,
});
}
//Configure Separate TemperatureSensor
if (zone.separateTemperature) {
const thisName = home.name + ' ' + zone.name + ' Temperature';
const uuid2 = UUIDGen.generate(thisName);
if (devices.has(uuid2)) {
Logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
thisName
);
} else {
let newConfig = { ...config };
newConfig.name = thisName;
newConfig.subtype = 'zone-temperature';
newConfig.model = newConfig.subtype;
newConfig.serialNumber = hashCode(zone.name);
devices.set(uuid2, newConfig);
}
}
//Configure Separate HumiditySensor
if (zone.separateHumidity) {
const thisName = home.name + ' ' + zone.name + ' Humidity';
const uuid2 = UUIDGen.generate(thisName);
if (devices.has(uuid2)) {
Logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
thisName
);
} else {
let newConfig = { ...config };
newConfig.name = thisName;
newConfig.subtype = 'zone-humidity';
newConfig.model = newConfig.subtype;
newConfig.serialNumber = hashCode(zone.name);
devices.set(uuid2, newConfig);
}
}
}
}
}
});
if (validOpenWindowSwitches.length) {
const name = home.name + ' Open Window';
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype = 'zone-window-switch';
config.openWindows = validOpenWindowSwitches;
config.model = config.subtype;
config.serialNumber = hashCode(name);
devices.set(uuid, config);
}
}
}
error = false;
//Configure Presence
if (home.presence && home.presence.user && home.presence.user.length) {
let valid_userTypes = ['MOTION', 'OCCUPANCY'];
let activeUser = 0;
home.presence.user.forEach((user) => {
if (user.active) {
if (!user.name) {
Logger.warn('There is no name configured for this user. This user will be skipped.', home.name);
error = true;
}
if (!error) {
const thisName = home.name + ' ' + user.name;
const uuid = UUIDGen.generate(thisName);
if (devices.has(uuid)) {
Logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
thisName
);
} else {
activeUser += 1;
let config = { ...accessoryConfig };
config.name = thisName;
config.subtype =
valid_userTypes.includes(user.accType) && user.accType === 'MOTION'
? 'presence-motion'
: 'presence-occupancy';
config.anyone = home.presence.anyone;
config.model = config.subtype;
config.serialNumber = hashCode(thisName);
devices.set(uuid, config);
}
}
}
});
//Coinfigure Anyone Sensor
if (activeUser && home.presence.anyone) {
const name = home.name + ' Anyone';
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype =
valid_userTypes.includes(config.accTypeAnyone) && config.accTypeAnyone === 'MOTION'
? 'presence-motion'
: 'presence-occupancy';
config.anyone = home.presence.anyone;
config.model = config.subtype;
config.serialNumber = hashCode(name);
devices.set(uuid, config);
}
}
}
error = false;
//Configure Weather
if (home.weather) {
//Configure Weather TemperatureSensor
if (home.weather.temperatureSensor) {
const name = home.name + ' Weather';
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype = 'weather-temperature';
config.model = 'Weather Temperature';
config.serialNumber = hashCode(name);
devices.set(uuid, config);
}
}
//Configure Weather SolarIntensity Lightbulb
if (home.weather.solarIntensity) {
const name = home.name + ' Solar Intensity';
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype =
home.weather.accTypeSolarIntensity === 'SENSOR' ? 'weather-lightsensor' : 'weather-lightbulb';
config.model = 'Solar Intensity';
config.serialNumber = hashCode(name);
devices.set(uuid, config);
}
}
}
error = false;
//Configure Extras
if (home.extras) {
if (activeZones) {
let validSwitches = [];
//Configure Central Switch
if (home.extras.centralSwitch) {
validSwitches.push({
name: 'Central',
sub: 'Central',
});
//Configure Boost Switch
if (home.extras.boostSwitch) {
validSwitches.push({
name: 'Boost',
sub: 'CentralBoost',
});
}
//Configure Shedule Switch
if (home.extras.sheduleSwitch) {
validSwitches.push({
name: 'Shedule',
sub: 'CentralShedule',
});
}
//Configure Turnoff Switch
if (home.extras.turnoffSwitch) {
validSwitches.push({
name: 'Off',
sub: 'CentralOff',
});
}
//Configure Turnoff Switch
if (home.extras.dummySwitch) {
validSwitches.push({
name: 'Dummy',
sub: 'CentralDummy',
});
}
}
if (validSwitches.length) {
const name = home.name + ' Central Switch';
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
name
);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype = 'extra-cntrlswitch';
config.runningInformation = home.extras.runningInformation;
config.rooms = home.zones.filter((zne) => zne && zne.id);
config.switches = validSwitches;
config.model = 'Central Switch';
config.serialNumber = hashCode(name);
devices.set(uuid, config);
}
}
}
//Configure Presence Lock
if (home.extras.presenceLock) {
const name = home.name + ' Presence Lock';
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn('Multiple devices are configured with this name. Duplicate devices will be skipped.', name);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype = home.extras.accTypePresenceLock === 'ALARM' ? 'extra-plock' : 'extra-plockswitch';
config.model = 'Presence Lock';
config.serialNumber = hashCode(name);
devices.set(uuid, config);
}
}
//Configure Child Lock
if (home.extras.childLockSwitches) {
let validSwitches = [];
home.extras.childLockSwitches.forEach((childLock) => {
if (childLock.active) {
if (!childLock.name) {
Logger.warn(
'There is no name configured for this child lock switch. This switch will be skipped.',
home.name
);
error = true;
}
if (!error) {
validSwitches.push(childLock);
}
}
});
if (validSwitches.length) {
const name = home.name + ' Child Lock';
const uuid = UUIDGen.generate(name);
if (devices.has(uuid)) {
Logger.warn(
'Multiple devices are configured with this name. Duplicate devices will be skipped.',
name
);
} else {
let config = { ...accessoryConfig };
config.name = name;
config.subtype = 'extra-childswitch';
config.childLocks = validSwitches;
config.model = config.subtype;
config.serialNumber = hashCode(name);
devices.set(uuid, config);
}
}
}
}
if (home.telegram && home.telegram.active && home.telegram.token && home.telegram.chatID) {
const telegramConfig = home.telegram;
telegramConfig.messages = home.telegram.messages || {};
const messages = {};
Object.keys(telegramConfig.messages)
.filter((msg) => Object.keys(telegramConfig.messages[msg]).length)
.map((msg) => {
messages[msg] = {
...telegramConfig.messages[msg],
};
});
telegram = new Telegram(telegramConfig, messages);
} else {
Logger.debug('Telegram is not or not correctly set up. Skip.');
}
deviceHandler.set(home.name, accessoryConfig);
}
});
}
return {
config: config,
devices: devices,
deviceHandler: deviceHandler,
telegram: telegram,
};
},
store: async function (config, storePath) {
const configJSON = await fs.readJson(storePath + '/config.json');
for (const i in configJSON.platforms)
if (configJSON.platforms[i].platform === 'TadoPlatform') configJSON.platforms[i] = config;
fs.writeJsonSync(storePath + '/config.json', configJSON, { spaces: 4 });
return;
},
};