UNPKG

@homebridge-plugins/homebridge-govee

Version:

Homebridge plugin to integrate Govee devices into HomeKit.

217 lines (200 loc) 6.16 kB
import { CMD } from './ble-protocol.js' import { k2rgb } from './colour.js' import { getDeviceCapabilities } from './device-capabilities.js' import { base64ToHex } from './functions.js' /** * Builds connection-specific command params from a high-level device command. * Returns { awsParams, bleParams, lanParams, openApiParams } any may be undefined. */ export function buildCommand(params, context) { switch (params.cmd) { case 'state': return buildStateCommand(params) case 'stateDual': return buildStateDualCommand(params) case 'stateOutlet': return buildStateOutletCommand(params, context) case 'stateHumi': case 'statePuri': return buildStateApplianceCommand(params) case 'stateHeat': return buildStateHeatCommand(params) case 'multiSync': case 'ptReal': return buildPtRealCommand(params) case 'openApi': return buildOpenApiCommand(params) case 'brightness': return buildBrightnessCommand(params, context) case 'color': return buildColorCommand(params, context) case 'colorTem': return buildColorTempCommand(params, context) case 'rgbScene': return buildSceneCommand(params) default: throw new Error('Invalid command') } } function buildStateCommand(params) { const isOn = params.value === 'on' return { awsParams: { cmd: 'turn', data: { val: isOn ? 1 : 0 } }, bleParams: { cmd: CMD.POWER, data: isOn ? 0x1 : 0x0 }, lanParams: { cmd: 'turn', data: { value: isOn ? 1 : 0 } }, openApiParams: { cmd: 'state', value: params.value }, } } function buildStateDualCommand(params) { return { awsParams: { cmd: 'turn', data: { val: params.value } }, openApiParams: { cmd: 'stateDual', value: params.value }, } } function buildStateOutletCommand(params, context) { const caps = getDeviceCapabilities(context.gvModel) return { awsParams: { cmd: 'turn', data: { val: params.value === 'on' ? caps.awsPowerOn : caps.awsPowerOff }, }, openApiParams: { cmd: 'stateOutlet', value: params.value }, } } function buildStateApplianceCommand(params) { return { awsParams: { cmd: 'turn', data: { val: params.value } }, bleParams: { cmd: CMD.POWER, data: params.value ? 0x1 : 0x0 }, openApiParams: { cmd: params.cmd, value: params.value }, } } function buildStateHeatCommand(params) { const fullCode = params.value ? 'MwEBAAAAAAAAAAAAAAAAAAAAADM=' : 'MwEAAAAAAAAAAAAAAAAAAAAAADI=' return { awsParams: { cmd: 'multiSync', data: { command: [fullCode] } }, bleParams: { cmd: 'ptReal', data: base64ToHex(fullCode) }, openApiParams: { cmd: 'stateHeat', value: params.value }, } } function buildPtRealCommand(params) { if (!params.value) { throw new Error(`Missing command value for ${params.cmd}`) } const result = { awsParams: { cmd: params.cmd, data: { command: [params.value] } }, bleParams: { cmd: 'ptReal', data: base64ToHex(params.value) }, } if (params.openApi) { result.openApiParams = { cmd: 'openApi', ...params.openApi } } return result } function buildOpenApiCommand(params) { if (!params.openApi?.instance) { throw new Error(`Missing openApi instance for ${params.cmd}`) } return { openApiParams: { cmd: 'openApi', ...params.openApi }, } } function buildBrightnessCommand(params, context) { const caps = getDeviceCapabilities(context.gvModel) return { awsParams: { cmd: 'brightness', data: { val: params.value }, }, bleParams: { cmd: CMD.BRIGHTNESS, data: Math.floor((params.value / 100) * caps.bleBrightnessScale), }, lanParams: { cmd: 'brightness', data: { value: params.value } }, openApiParams: { cmd: 'brightness', value: params.value }, } } function buildColorCommand(params, context) { const caps = getDeviceCapabilities(context.gvModel) const { r, g, b } = params.value let awsParams switch (context.awsColourMode) { case 'rgb': awsParams = { cmd: 'color', data: params.value } break case 'redgreenblue': awsParams = { cmd: 'color', data: { red: r, green: g, blue: b } } break default: awsParams = { cmd: 'colorwc', data: { color: { r, g, b, red: r, green: g, blue: b }, colorTemInKelvin: 0, }, } break } return { awsParams, bleParams: { cmd: CMD.COLOR_MODE, data: [...caps.bleColorCmd, r, g, b, ...caps.bleColorCmdSuffix], }, lanParams: { cmd: 'colorwc', data: { color: { r, g, b }, colorTemInKelvin: 0 }, }, openApiParams: { cmd: 'color', value: params.value }, } } function buildColorTempCommand(params, context) { const caps = getDeviceCapabilities(context.gvModel) const [r, g, b] = k2rgb(params.value) let awsParams switch (context.awsColourMode) { case 'rgb': awsParams = { cmd: 'colorTem', data: { colorTemInKelvin: params.value, color: { r, g, b } }, } break case 'redgreenblue': awsParams = { cmd: 'colorTem', data: { color: { red: r, green: g, blue: b }, colorTemInKelvin: params.value }, } break default: awsParams = { cmd: 'colorwc', data: { color: { r, g, b }, colorTemInKelvin: params.value }, } break } return { awsParams, bleParams: { cmd: CMD.COLOR_MODE, data: [...caps.bleColorCmd, 0xFF, 0xFF, 0xFF, 0x01, r, g, b], }, lanParams: { cmd: 'colorwc', data: { color: { r, g, b }, colorTemInKelvin: params.value }, }, openApiParams: { cmd: 'colorTem', value: params.value }, } } function buildSceneCommand(params) { const result = {} if (params.value[0]) { const splitCode = params.value[0].split(',') result.awsParams = { cmd: 'ptReal', data: { command: splitCode } } result.lanParams = { cmd: 'ptReal', data: { command: splitCode } } } if (params.value[1]) { result.bleParams = { cmd: 'ptReal', data: params.value[1] } } if (params.openApi) { result.openApiParams = { cmd: 'openApi', ...params.openApi } } return result }