-
Notifications
You must be signed in to change notification settings - Fork 89.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WWST-4667] Qubino 3 Phase Meter integration (#43205)
* New DTHes to support Qubino 3 Phase Meter * Added raw description, changed child device DTH other minor fixes
- Loading branch information
1 parent
92cbc53
commit ef649f7
Showing
2 changed files
with
245 additions
and
0 deletions.
There are no files selected for viewing
195 changes: 195 additions & 0 deletions
195
devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/** | ||
* Copyright 2020 SmartThings | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at: | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed | ||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License | ||
* for the specific language governing permissions and limitations under the License. | ||
* | ||
*/ | ||
metadata { | ||
definition (name: "Qubino 3 Phase Meter", namespace: "qubino", author: "SmartThings", ocfDeviceType: "x.com.st.d.energymeter", mcdSync: true) { | ||
capability "Energy Meter" | ||
capability "Power Meter" | ||
capability "Configuration" | ||
capability "Sensor" | ||
capability "Health Check" | ||
capability "Refresh" | ||
|
||
fingerprint mfr: "0159", prod: "0007", model: "0054", deviceJoinName: "Qubino Energy Monitor" //Qubino 3 Phase Meter | ||
// zw:L type:3103 mfr:0159 prod:0007 model:0054 ver:1.00 zwv:4.61 lib:03 cc:5E,55,86,73,56,98,9F,72,5A,70,60,85,8E,59,32,6C,7A epc:4 | ||
} | ||
|
||
// tile definitions | ||
tiles(scale: 2) { | ||
multiAttributeTile(name:"power", type: "generic", width: 6, height: 4){ | ||
tileAttribute("device.power", key: "PRIMARY_CONTROL") { | ||
attributeState("default", label:'${currentValue} W') | ||
} | ||
tileAttribute("device.energy", key: "SECONDARY_CONTROL") { | ||
attributeState("default", label:'${currentValue} kWh') | ||
} | ||
} | ||
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat",width: 2, height: 2) { | ||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" | ||
} | ||
standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat",width: 2, height: 2) { | ||
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" | ||
} | ||
|
||
main (["power","energy"]) | ||
details(["power","energy","refresh", "configure"]) | ||
} | ||
} | ||
|
||
def installed() { | ||
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) | ||
|
||
state.numberOfMeters = 3 | ||
|
||
if (!childDevices) { | ||
addChildMeters(state.numberOfMeters) | ||
} | ||
|
||
response(refresh()) | ||
} | ||
|
||
def updated() { | ||
response(refresh()) | ||
} | ||
|
||
def ping() { | ||
refresh() | ||
} | ||
|
||
def parse(String description) { | ||
def result = null | ||
def cmd = zwave.parse(description) | ||
if (cmd) { | ||
result = createEvent(zwaveEvent(cmd)) | ||
} | ||
log.debug "Parse returned ${result?.descriptionText}" | ||
return result | ||
} | ||
|
||
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { | ||
def encapsulatedCommand = cmd.encapsulatedCommand(versions) | ||
if (encapsulatedCommand) { | ||
zwaveEvent(encapsulatedCommand) | ||
} else { | ||
log.warn "Unable to extract encapsulated cmd from $cmd" | ||
createEvent(descriptionText: cmd.toString()) | ||
} | ||
} | ||
|
||
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { | ||
log.debug "Multichannel command ${cmd}" + (ep ? " from endpoint $ep" : "") | ||
if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message | ||
// Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header | ||
cmd.parameter = cmd.parameter.drop(2) | ||
// Updated Command Class/Command now with the remaining bytes | ||
cmd.commandClass = cmd.parameter[0] | ||
cmd.command = cmd.parameter[1] | ||
cmd.parameter = cmd.parameter.drop(2) | ||
} | ||
def encapsulatedCommand = cmd.encapsulatedCommand() | ||
zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) | ||
} | ||
|
||
def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, endpoint = null) { | ||
handleMeterReport(cmd, endpoint) | ||
} | ||
|
||
private handleMeterReport(cmd, endpoint) { | ||
def event = createMeterEventMap(cmd) | ||
if (endpoint && endpoint > 1) { | ||
String childDni = "${device.deviceNetworkId}:${endpoint - 1}" | ||
def child = childDevices.find { it.deviceNetworkId == childDni } | ||
child?.sendEvent(event) | ||
} else { | ||
createEvent(event) | ||
} | ||
} | ||
|
||
private createMeterEventMap(cmd) { | ||
def eventMap = [:] | ||
if (cmd.scale == 0) { | ||
eventMap.name = "energy" | ||
eventMap.value = cmd.scaledMeterValue | ||
eventMap.unit = "kWh" | ||
} else if (cmd.scale == 2) { | ||
eventMap.name = "power" | ||
eventMap.value = Math.round(Math.abs(cmd.scaledMeterValue)) | ||
eventMap.unit = "W" | ||
} | ||
eventMap | ||
} | ||
|
||
def zwaveEvent(physicalgraph.zwave.Command cmd) { | ||
// Handles all Z-Wave commands we aren't interested in | ||
log.warn "Not handled Z-Wave command: ${cmd}" | ||
[:] | ||
} | ||
|
||
private encap(cmd, endpoint = null) { | ||
if (cmd) { | ||
if (endpoint) { | ||
cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) | ||
} | ||
|
||
if (zwaveInfo.zw.contains("s")) { | ||
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() | ||
} else { | ||
cmd.format() | ||
} | ||
} | ||
} | ||
|
||
def refresh() { | ||
delayBetween([ | ||
encap(zwave.meterV3.meterGet(scale: 0)), | ||
encap(zwave.meterV3.meterGet(scale: 2)) | ||
]) | ||
} | ||
|
||
def configure() { | ||
log.debug "configure() has been called" | ||
encap(zwave.configurationV1.configurationSet(parameterNumber: 42, size: 2, scaledConfigurationValue: 1800)) // Report energy consumption every 30 minutes | ||
} | ||
|
||
private addChildMeters(numberOfMeters) { | ||
for (def endpoint : 1..numberOfMeters) { | ||
try { | ||
String childDni = "${device.deviceNetworkId}:$endpoint" | ||
def componentLabel = device.displayName + " ${endpoint}" | ||
addChildDevice("smartthings", "Child Energy Meter", childDni, device.getHub().getId(), [ | ||
completedSetup : true, | ||
label : componentLabel, | ||
isComponent : true, | ||
componentName : "endpointMeter$endpoint", | ||
componentLabel : "Endpoint Meter $endpoint" | ||
]) | ||
} catch (Exception e) { | ||
log.warn "Exception: ${e}" | ||
} | ||
} | ||
} | ||
|
||
private getMeterId(deviceNetworkId) { | ||
def split = deviceNetworkId?.split(":") | ||
return (split.length > 1) ? split[1] as Integer : null | ||
} | ||
|
||
private childRefresh(deviceNetworkId) { | ||
def meterId = getMeterId(deviceNetworkId) | ||
if (switchId != null) { | ||
sendHubCommand delayBetween([ | ||
encap(zwave.meterV3.meterGet(scale: 0), meterId), | ||
encap(zwave.meterV3.meterGet(scale: 2), meterId) | ||
]) | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* Copyright 2020 SRPOL | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at: | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed | ||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License | ||
* for the specific language governing permissions and limitations under the License. | ||
* | ||
*/ | ||
metadata { | ||
definition(name: "Child Energy Meter", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-switch-power-energy") { | ||
capability "Power Meter" | ||
capability "Energy Meter" | ||
capability "Refresh" | ||
capability "Actuator" | ||
capability "Sensor" | ||
capability "Health Check" | ||
} | ||
|
||
tiles(scale: 2) { | ||
valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { | ||
state "default", label:'${currentValue} W' | ||
} | ||
valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { | ||
state "default", label:'${currentValue} kWh' | ||
} | ||
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { | ||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" | ||
} | ||
|
||
main(["switch"]) | ||
details(["power","energy","refresh"]) | ||
} | ||
} | ||
|
||
def refresh() { | ||
parent.childRefresh(device.deviceNetworkId) | ||
} | ||
|
||
def ping() { | ||
refresh() | ||
} | ||
|
||
def installed() { | ||
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [hubHardwareId: device.hub.hardwareID]) | ||
} |