/**
* Copyright 2022 SmartThings
*
* Imported for Hubitat Elevation platform by kkossev 2022/11/01 1:38 PM ver. 2.0.1
*
* 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.
*
*/
import hubitat.zigbee.zcl.DataType
metadata {
definition (name: "SiHAS Zigbee Power Meter", namespace: "shinasys", author: "SHINA SYSTEM") {
capability "Energy Meter"
capability "Power Meter"
capability "Refresh"
capability "Sensor"
capability "Configuration"
capability "Voltage Measurement"
capability "Current Meter"
capability "Temperature Measurement"
capability "Switch"
attribute "powerFactor", "number"
fingerprint profileId:"0104", endpointId:"01", inClusters:"0000,0004,0003,0B04,0702,0402", outClusters:"0004,0019", model:"PMM-300Z1", manufacturer:"ShinaSystem", deviceJoinName: "SiHAS Power Meter PMM-300Z1" // SIHAS Power Meter 01 0104 0000 01 05 0000 0004 0003 0B04 0702 02 0004 0019
fingerprint profileId:"0104", endpointId:"01", inClusters:"0000,0004,0003,0B04,0702,0402", outClusters:"0004,0019", model:"PMM-300Z2", manufacturer:"ShinaSystem", deviceJoinName: "SiHAS Energy Monitor PMM-300Z2" // Single Phase, SIHAS Power Meter 01 0104 0000 01 06 0000 0004 0003 0B04 0702 0402 02 0004 0019
fingerprint profileId:"0104", endpointId:"01", inClusters:"0000,0004,0003,0B04,0702,0402", outClusters:"0004,0019", model:"PMM-300Z3", manufacturer:"ShinaSystem", deviceJoinName: "SiHAS Energy Monitor PMM-300Z3" // Three Phase, SIHAS Power Meter 01 0104 0000 01 06 0000 0004 0003 0B04 0702 0402 02 0004 0019
preferences {
section {
input (name: "logEnable", type: "bool", title: "Debug logging", description: "Debug information, useful for troubleshooting. Recommended value is false", defaultValue: false)
input (name: "txtEnable", type: "bool", title: "Description text logging", description: "Display sensor states in HE log page. Recommended value is true", defaultValue: true)
}
}
}
}
def getATTRIBUTE_READING_INFO_SET() { 0x0000 }
def getATTRIBUTE_HISTORICAL_CONSUMPTION() { 0x0400 }
def getATTRIBUTE_ACTIVE_POWER() { 0x050B }
def getATTRIBUTE_FREQUENCY() { 0x0300 }
def getATTRIBUTE_VOLTAGE() { 0x0505 }
def getATTRIBUTE_CURRENT() { 0x0508 }
def getATTRIBUTE_POWERFACTOR() { 0x0510 }
def getTEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE() { 0x0000 }
def convertHexToInt24Bit(value) {
int result = zigbee.convertHexToInt(value)
if (result & 0x800000) {
result |= 0xFF000000
}
return result
}
def parse(String description) {
if (settings?.logEnable) log.debug "${device.displayName} description is $description"
def event = zigbee.getEvent(description)
def descMap = zigbee.parseDescriptionAsMap(description)
if (event) {
if (settings?.logEnable) log.info "${device.displayName} event enter:$event"
if (event.name == "switch") {
return sendEvent(event)
} else if (event.name == "temperature") {
return sendEvent(event)
}
else {
if (settings?.logEnable) log.warn "${device.displayName} unprocessed event: $event"
}
}
if (descMap) {
List result = []
if (settings?.logEnable) log.debug "${device.displayName} Desc Map: $descMap"
List attrData = [[clusterInt: descMap.clusterInt, attrInt: descMap.attrInt, value: descMap.value]]
descMap.additionalAttrs.each {
attrData << [clusterInt: descMap.clusterInt, attrInt: it.attrInt, value: it.value]
}
attrData.each {
def map = [:]
if (it.value != null) {
if (it.clusterInt == zigbee.METERING_CLUSTER && it.attrInt == ATTRIBUTE_HISTORICAL_CONSUMPTION) {
map.name = "power"
map.value = convertHexToInt24Bit(it.value)/powerDivisor
map.unit = "W"
} else if (it.clusterInt == zigbee.METERING_CLUSTER && it.attrInt == ATTRIBUTE_READING_INFO_SET) {
map.name = "energy"
map.value = zigbee.convertHexToInt(it.value)/energyDivisor
map.unit = "kWh"
} else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_FREQUENCY) {
map.name = "frequency"
map.value = zigbee.convertHexToInt(it.value)/frequencyDivisor
map.unit = "Hz"
} else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_VOLTAGE) {
map.name = "voltage"
map.value = zigbee.convertHexToInt(it.value)/voltageDivisor
map.unit = "V"
} else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_CURRENT) {
map.name = "amperage"
map.value = zigbee.convertHexToInt(it.value)/currentDivisor
map.unit = "A"
} else if (it.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER && it.attrInt == ATTRIBUTE_POWERFACTOR) {
map.name = "powerFactor"
map.value = (byte) zigbee.convertHexToInt(it.value)/powerFactorDivisor
map.unit = "%"
} else if (it.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && it.attrInt == TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE) {
map.name = "temperature"
map.unit = getTemperatureScale()
map.value = zigbee.parseHATemperatureValue("temperature: " + (zigbee.convertHexToInt(it.value)), "temperature: ", tempScale)
if (settings?.logEnable) log.debug "${device.displayName}: Reported temperature is ${map.value}°$map.unit"
}
}
if (map) {
result << createEvent(map)
if (settings?.txtEnable) log.info "${device.displayName} ${map.name} is ${map.value} ${map.unit}"
}
if (settings?.logEnable) log.debug "${device.displayName} Parse returned $map result is: ${result}"
}
return result
}
}
def off() {
if (settings?.logEnable) log.debug "${device.displayName} sending off command"
zigbee.off()
}
def on() {
if (settings?.logEnable) log.debug "${device.displayName} sending on command"
zigbee.on()
}
def refresh() {
if (settings?.txtEnable) log.debug "${device.displayName} refresh "
zigbee.onOffRefresh() +
zigbee.electricMeasurementPowerRefresh() +
zigbee.readAttribute(zigbee.METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_CURRENT) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_POWERFACTOR) +
zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE)
}
def configure() {
def configCmds = []
// this device will send instantaneous demand and current summation delivered every 10 minutes
if (settings?.txtEnable) log.debug "${device.displayName} Configuring Reporting"
configCmds = zigbee.onOffConfig() +
zigbee.configureReporting(zigbee.METERING_CLUSTER, ATTRIBUTE_HISTORICAL_CONSUMPTION, DataType.INT24, 5, 600, 1) +
zigbee.configureReporting(zigbee.METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 5, 600, 1) +
zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_FREQUENCY, DataType.UINT16, 10, 600, 3) + /* 3 unit : 0.3Hz */
zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_VOLTAGE, DataType.UINT16, 5, 600, 3) + /* 3 unit : 0.3V */
zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_CURRENT, DataType.UINT16, 5, 600, 1) + /* 1 unit : 0.01A */
zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, ATTRIBUTE_POWERFACTOR, DataType.INT8, 10, 600, 1) + /* 1 unit : 0.1% */
zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, TEMPERATURE_MEASUREMENT_MEASURED_VALUE_ATTRIBUTE, DataType.INT16, 20, 300, 10 /* 1 uint : 0.1C */)
return configCmds + refresh()
}
private getActivePowerDivisor() { 1 }
private getPowerDivisor() { 1 }
private getEnergyDivisor() { 1000 }
private getFrequencyDivisor() { 10 }
private getVoltageDivisor() { 10 }
private getCurrentDivisor() { 100 }
private getPowerFactorDivisor() { 1 }