homebridge-tado-ac
Version:
tado° Smart AC Control plugin for homebridge: https://github.com/nfarina/homebridge
215 lines (165 loc) • 5.55 kB
JavaScript
function fanLevelToHK(value, fanLevels) {
if (value === 'AUTO')
return 0
fanLevels = fanLevels.filter(level => level !== 'AUTO')
const totalLevels = fanLevels.length
const valueIndex = fanLevels.indexOf(value) + 1
return Math.round(100 * valueIndex / totalLevels)
}
function HKToFanLevel(value, fanLevels) {
let selected = 'AUTO'
if (!fanLevels.includes('AUTO'))
selected = fanLevels[0]
if (value !== 0) {
fanLevels = fanLevels.filter(level => level !== 'AUTO')
const totalLevels = fanLevels.length
for (let i = 0; i < fanLevels.length; i++) {
if (value <= (100 * (i + 1) / totalLevels)) {
selected = fanLevels[i]
break
}
}
}
return selected
}
function toFahrenheit(value) {
return Math.round((value * 1.8) + 32)
}
module.exports = {
deviceInformation: device => {
return {
id: device.id,
model: device.devices[0].deviceType,
serial: device.devices[0].serialNo.toString(),
manufacturer: 'tado GmbH',
appId: 'com.tado.tadoapp',
roomName: device.name,
temperatureUnit: device.temperatureUnit,
filterService: false,
installation: device.installation
}
},
userInformation: user => {
if (user.id === 'anyoneSensor')
return {
id: 'anyoneSensor',
name: 'Anyone',
model: 'anyoneSensor',
serial: '101010',
manufacturer: 'tado GmbH',
appId: 'com.tado.tadoapp'
}
const mobileDevice = user.mobileDevices.find(device => device.settings.geoTrackingEnabled)
return {
id: user.id,
name: user.name,
model: mobileDevice.name,
serial: mobileDevice.id.toString(),
manufacturer: 'tado GmbH',
appId: 'com.tado.tadoapp'
}
},
capabilities: device => {
const capabilities = {}
for (const [key, modeCapabilities] of Object.entries(device.capabilities)) {
// Mode options are COOL, HEAT, AUTO, FAN, DRY
const mode = key.toUpperCase()
if (!['COOL', 'HEAT', 'AUTO', 'FAN', 'DRY'].includes(mode))
continue
capabilities[mode] = {}
// set temperatures min & max
if (['COOL', 'HEAT', 'AUTO'].includes(mode) && modeCapabilities.temperatures && modeCapabilities.temperatures.celsius) {
capabilities[mode].temperatures = {
CELSIUS: {
min: modeCapabilities.temperatures.celsius.min,
max: modeCapabilities.temperatures.celsius.max
},
FAHRENHEIT: {
min: modeCapabilities.temperatures.fahrenheit.min,
max: modeCapabilities.temperatures.fahrenheit.max
}
}
}
// set fanSpeeds
if (modeCapabilities.fanSpeeds && modeCapabilities.fanSpeeds.length) {
capabilities[mode].fanSpeeds = modeCapabilities.fanSpeeds.reverse()
// set AUTO fanSpeed
if (capabilities[mode].fanSpeeds.includes('AUTO'))
capabilities[mode].autoFanSpeed = true
else
capabilities[mode].autoFanSpeed = false
}
// set swing
if (modeCapabilities.verticalSwing) {
capabilities[mode].swing = true
}
}
return capabilities
},
acState: (device) => {
const state = {
active: (device.state.setting.power === 'ON'),
mode: device.state.setting.mode || 'OFF',
targetTemperature: device.state.setting.temperature ? device.state.setting.temperature.celsius : null,
currentTemperature: device.state.sensorDataPoints.insideTemperature.celsius,
relativeHumidity: device.state.sensorDataPoints.humidity.percentage,
tadoMode: device.state.overlayType,
manualControl: !!device.state.overlay
}
const modeCapabilities = device.capabilities[state.mode]
state.swing = (state.mode === 'OFF' || !modeCapabilities.swing || !device.state.setting.swing || device.state.setting.swing === 'OFF') ?
'SWING_DISABLED' : 'SWING_ENABLED'
state.fanSpeed = (state.mode === 'OFF' || !modeCapabilities.fanSpeeds || !device.state.setting.fanSpeed) ?
0 : fanLevelToHK(device.state.setting.fanSpeed, modeCapabilities.fanSpeeds)
return state
},
weatherState: weather => {
const state = {
outsideTemperature: weather.outsideTemperature.celsius,
solarIntensity: weather.solarIntensity.percentage
}
return state
},
occupancyState: user => {
const mobileDevice = user.mobileDevices.find(device => device.settings.geoTrackingEnabled && device.location)
const state = {
occupancy: (mobileDevice && mobileDevice.location && mobileDevice.location.atHome) ? 'OCCUPANCY_DETECTED' : 'OCCUPANCY_NOT_DETECTED'
}
return state
},
anyoneOccupancyState: allUsersStates => {
const occupied = Object.values(allUsersStates).find(user => user.occupancy === 'OCCUPANCY_DETECTED')
const state = {
occupancy: occupied ? 'OCCUPANCY_DETECTED' : 'OCCUPANCY_NOT_DETECTED'
}
return state
},
tadoOverlay: (platform, device, state) => {
const overlay = {
termination: {
type: platform.tadoMode
},
setting: {
type: 'AIR_CONDITIONING',
power: state.active ? 'ON' : 'OFF'
}
}
if (platform.tadoMode === 'TIMER')
overlay.termination.durationInSeconds = platform.durationInMinutes * 60
// returning off state
if (!state.active)
return overlay
overlay.setting.mode = state.mode
if (!state.targetTemperature)
state.targetTemperature = 25
overlay.setting.temperature = {
fahrenheit: toFahrenheit(state.targetTemperature),
celsius: state.targetTemperature
}
if ('swing' in device.capabilities[state.mode])
overlay.setting.swing = state.swing === 'SWING_ENABLED' ? 'ON' : 'OFF'
if ('fanSpeeds' in device.capabilities[state.mode])
overlay.setting.fanSpeed = HKToFanLevel(state.fanSpeed, device.capabilities[state.mode].fanSpeeds)
return overlay
}
}