Skip to content

Commit

Permalink
feat: correctly parse currentColor value and improve rgb discovery (#…
Browse files Browse the repository at this point in the history
…568)


Co-authored-by: V. Aretakis <[email protected]>
Co-authored-by: Daniel Lando <[email protected]>
  • Loading branch information
3 people authored Feb 26, 2021
1 parent 0cabbc6 commit 7bedd3b
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 85 deletions.
22 changes: 3 additions & 19 deletions hass/configurations.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,20 @@ module.exports = {
}
},
// Light https://www.home-assistant.io/components/light.mqtt
light_rgb_switch: {
type: 'light',
object_id: 'rgb_switch',
discovery_payload: {
state_topic: true,
command_topic: true,
rgb_command_template: "{{ '#%02x%02x%02x' | format(red, green, blue)}}",
rgb_command_topic: true,
rgb_state_topic: true,
rgb_value_template:
'{{ value_json.value[0:2] | int(0, 16) }},{{ value_json.value[2:4] | int(0, 16) }},{{ value_json.value[4:6] | int(0, 16) }}'
}
},
light_rgb_dimmer: {
type: 'light',
object_id: 'rgb_dimmer',
discovery_payload: {
state_topic: true,
command_topic: true,
brightness_state_topic: true,
brightness_command_topic: true,
on_command_type: 'brightness',
state_value_template: '{{ "OFF" if value_json.value == 0 else "ON" }}',
brightness_value_template: '{{ value_json.value }}',
brightness_scale: 99,
rgb_command_template: '{{ "#%02x%02x%02x" | format(red, green, blue)}}',
rgb_command_topic: true,
rgb_state_topic: true,
rgb_command_template:
"{{ {'red': red, 'green': green, 'blue': blue}|to_json }}",
rgb_value_template:
'{{ value_json.value[0:2] | int(0, 16) }},{{ value_json.value[2:4] | int(0, 16) }},{{ value_json.value[4:6] | int(0, 16) }}'
'{{ value_json.value.red }},{{ value_json.value.green }},{{ value_json.value.blue }}'
}
},
light_dimmer: {
Expand Down
140 changes: 86 additions & 54 deletions lib/Gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -768,46 +768,88 @@ function setDiscoveryValue (payload, prop, node) {
/**
* Check if this node supports rgb and if so add it to discovery configuration
*
* @param {*} cfg the discovery configuration
* @param {import('../types').Z2MNode} node the node
* @param {import('../types').Z2MValueId} valueId the valueId
* @returns {any} a configuration if the rgb dimmer is added, false otherwise
* @param {import('../types').Z2MValueId} currentColorValue the valueId of the `currentColor` Color CC
* @returns {any} a configuration if the rgb dimmer is added
*/
function addRgbDimmer (cfg, node, valueId) {
const rgbID = `51-${valueId.endpoint || 0}-hexColor`
const rgb = node.values[rgbID]
if (rgb) {
cfg = copy(cfg)
cfg.discovery_payload.rgb_state_topic = this.mqtt.getTopic(
this.valueTopic(node, rgb)
)
cfg.discovery_payload.rgb_command_topic =
cfg.discovery_payload.rgb_state_topic + '/set'
cfg.values = [rgbID]

const whiteID = `51-${valueId.endpoint || 0}-currentColor-0`
const whiteValue = node.values[whiteID]

if (whiteValue) {
const whiteIDWrite = `51-${valueId.endpoint || 0}-targetColor-0`
const whiteValueWrite = node.values[whiteIDWrite]
cfg.discovery_payload.white_value_state_topic = this.mqtt.getTopic(
this.valueTopic(node, whiteValue)
)
cfg.discovery_payload.white_value_scale = whiteValue.max
cfg.discovery_payload.white_value_template = '{{ value_json.value }}'
cfg.discovery_payload.white_value_command_topic = this.mqtt.getTopic(
this.valueTopic(node, whiteValueWrite),
true
)
function addRgbColorSwitch (node, currentColorValue) {
const cfg = copy(hassCfg.light_rgb_dimmer)

cfg.values.push(whiteID, whiteIDWrite)
}
const currentColorTopics = this.valueTopic(node, currentColorValue, true)

const endpoint = currentColorValue.endpoint

// current color values are automatically added later in discoverValue function
cfg.values = []

cfg.discovery_payload.rgb_state_topic = this.mqtt.getTopic(
currentColorTopics.topic
)
cfg.discovery_payload.rgb_command_topic = this.mqtt.getTopic(
currentColorTopics.targetTopic,
true
)

// The following part of code, checks if ML or Binary works. If one exists the other
let brightnessValue = false
let switchValue = false
if (node.values[`38-${endpoint}-currentValue`]) {
brightnessValue = `38-${endpoint}-currentValue`
// Next if is about Fibaro like RGBW which use the endpoint 1 as multilevel
} else if (endpoint === 0 && node.values['38-1-currentValue']) {
brightnessValue = '38-1-currentValue'
} else if (node.values[`37-${endpoint}-currentValue`]) {
switchValue = `37-${endpoint}-currentValue`
}

/* Find the control switch of the device Brightness or Binary
If multilevel is not there use binary
Some devices use also endpoint + 1 as on/off/brightness... try to guess that too!
*/
let discoveredStateTopic
let discoveredCommandTopic

if (brightnessValue || switchValue) {
const vID = brightnessValue || switchValue

const valueIdState = node.values[vID]
const topics = this.valueTopic(node, valueIdState, true)

cfg.values.push(vID, valueIdState.targetValue)

return cfg
discoveredStateTopic = this.mqtt.getTopic(topics.topic)
discoveredCommandTopic = this.mqtt.getTopic(topics.targetTopic, true)
}

return false
if (brightnessValue) {
cfg.discovery_payload.brightness_state_topic = discoveredStateTopic
cfg.discovery_payload.brightness_command_topic = discoveredCommandTopic
cfg.discovery_payload.state_topic = discoveredStateTopic
cfg.discovery_payload.command_topic = discoveredCommandTopic
} else if (switchValue) {
cfg.discovery_payload.state_topic = discoveredStateTopic
cfg.discovery_payload.command_topic = discoveredCommandTopic

cfg.discovery_payload.state_value_template = '{{ value_template.json }}'
cfg.discovery_payload.on_command_type = 'last'
}

const whiteValue = node.values[`51-${endpoint}-currentcolor-0`]

// if whitevalue exists, use currentColor value to get/set white
if (whiteValue && currentColorValue) {
// still use currentColor but change the template
cfg.discovery_payload.color_temp_state_topic =
cfg.discovery_payload.rgb_state_topic
cfg.discovery_payload.color_temp_command_topic =
cfg.discovery_payload.rgb_command_topic

cfg.discovery_payload.color_temp_command_template =
"{{ {'warmWhite': ((value - 245)|round(0)), 'coldWhite': (255 - (value - 245))|round(0))}|to_json }}"
cfg.discovery_payload.color_temp_value_template =
"{{ '%03d%03d' | format((value_json.value.warmWhite || 0), (value_json.value.coldWhite || 0)) }}"
}
return cfg
}

/**
Expand Down Expand Up @@ -1634,10 +1676,7 @@ Gateway.prototype.discoverValue = function (node, vId) {
case CommandClasses['All Switch']:
case CommandClasses['Binary Toggle Switch']:
if (valueId.isCurrentValue) {
cfg = addRgbDimmer.call(this, hassCfg.light_rgb_switch, node, valueId)
if (!cfg) {
cfg = copy(hassCfg.switch)
}
cfg = copy(hassCfg.switch)
} else return
break
case CommandClasses['Barrier Operator']:
Expand Down Expand Up @@ -1674,17 +1713,7 @@ Gateway.prototype.discoverValue = function (node, vId) {
cfg.discovery_payload.payload_open = 99
cfg.discovery_payload.payload_close = 0
} else {
// ... otherwise use a light dimmer configuration
// brightness level
cfg = addRgbDimmer.call(
this,
hassCfg.light_rgb_dimmer,
node,
valueId
)
if (!cfg) {
cfg = copy(hassCfg.light_dimmer)
}
cfg = copy(hassCfg.light_dimmer)
cfg.discovery_payload.brightness_state_topic = getTopic
cfg.discovery_payload.brightness_command_topic = setTopic
}
Expand All @@ -1711,6 +1740,14 @@ Gateway.prototype.discoverValue = function (node, vId) {
return
}
break
case CommandClasses['Color Switch']:
if (
valueId.property === 'currentColor' &&
valueId.propertyKey === undefined
) {
cfg = addRgbColorSwitch.call(this, node, valueId)
} else return
break
case CommandClasses['Central Scene']:
case CommandClasses['Scene Activation']:
cfg = copy(hassCfg.central_scene)
Expand Down Expand Up @@ -2025,11 +2062,6 @@ Gateway.prototype.discoverValue = function (node, vId) {
if (valueConf.icon) cfg.discovery_payload.icon = valueConf.icon
}
break
case 'color':
if (valueId.property === 'hexColor') {
cfg = addRgbDimmer.call(this, hassCfg.light_rgb_switch, node, valueId)
} else return
break
default:
return
}
Expand Down
4 changes: 4 additions & 0 deletions lib/ZwaveClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,10 @@ function initNode (zwaveNode) {
node.manufacturer = deviceConfig.manufacturer
node.firmwareVersion = zwaveNode.firmwareVersion
node.zwaveVersion = zwaveNode.version
node.zwavePlusVersion = zwaveNode.zwavePlusVersion
node.nodeType = zwaveNode.nodeType
node.roleType = zwaveNode.roleType
node.endpointsCount = zwaveNode.getEndpointCount()
node.isSecure = zwaveNode.isSecure
node.isBeaming = zwaveNode.isBeaming
node.isListening = zwaveNode.isListening
Expand Down
62 changes: 51 additions & 11 deletions src/components/ValueId.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,38 @@

<div v-else>
<v-text-field
v-if="
!value.list &&
(value.type === 'number' ||
value.type === 'string' ||
value.type === 'any')
"
:type="value.type === 'number' ? 'number' : 'text'"
v-if="!value.list && value.type === 'string'"
:append-outer-icon="!disable_send ? 'send' : null"
:suffix="value.unit"
persistent-hint
:hint="help"
v-model="value.newValue"
@click:append-outer="updateValue(value)"
></v-text-field>

<v-text-field
v-if="!value.list && value.type === 'number'"
type="number"
:append-outer-icon="!disable_send ? 'send' : null"
:suffix="value.unit"
:min="value.min != value.max ? value.min : null"
:step="1"
persistent-hint
:max="value.min != value.max ? value.max : null"
:hint="help"
v-model="value.newValue"
v-model.number="value.newValue"
@click:append-outer="updateValue(value)"
></v-text-field>

<v-text-field
v-if="!value.list && value.type === 'any'"
:append-outer-icon="!disable_send ? 'send' : null"
:suffix="value.unit"
persistent-hint
:error="!!error"
:error-messages="error"
:hint="help"
v-model="parsedAny"
@click:append-outer="updateValue(value)"
></v-text-field>

Expand Down Expand Up @@ -174,7 +191,8 @@ export default {
data () {
return {
durations: ['seconds', 'minutes'],
menu: false
menu: false,
error: false
}
},
computed: {
Expand Down Expand Up @@ -202,15 +220,37 @@ export default {
)
},
color: {
// getter
get: function () {
return '#' + (this.value.newValue || 'ffffff').toUpperCase()
},
// setter
set: function (v) {
this.value.newValue = v ? v.substr(1, 7) : null
}
},
parsedAny: {
get: function () {
if (this.value.type === 'any') {
if (typeof this.value.newValue === 'object') {
return JSON.stringify(this.value.newValue)
}
}
return this.value.newValue
},
set: function (v) {
if (this.value.type === 'any') {
if (typeof this.value.value === 'object') {
try {
this.value.newValue = JSON.parse(v)
this.error = false
} catch (error) {
this.error = 'Value not valid'
}
}
} else {
this.value.newValue = v
}
}
},
pickerStyle () {
if (this.value.type !== 'color') return null
return {
Expand Down
7 changes: 6 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
ValueID,
ValueType,
ZWaveNode,
ZWaveOptions
ZWaveOptions,
ZWavePlusNodeType
} from 'zwave-js'

export type Z2MValueIdState = {
Expand Down Expand Up @@ -97,6 +98,10 @@ export type Z2MNode = {
manufacturer: string
firmwareVersion: string
zwaveVersion: string
zwavePlusVersion: number | undefined
nodeType: ZWavePlusNodeType | undefined
roleType: ZWavePlusRoleType | undefined
endpointsCount: number
isSecure: boolean
isBeaming: boolean
isListening: boolean
Expand Down

0 comments on commit 7bedd3b

Please sign in to comment.