mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-20 13:20:53 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a29c8efd1 | ||
|
|
e5841fb3cb | ||
|
|
805b870447 | ||
|
|
10245315ee | ||
|
|
0b239d4686 | ||
|
|
9374290d64 | ||
|
|
c45129170a | ||
|
|
53406ada8e | ||
|
|
ffd0dd1545 | ||
|
|
5c1236a21a | ||
|
|
0911651f71 | ||
|
|
9cc92b1987 | ||
|
|
1e27dc1824 | ||
|
|
4bf3679942 | ||
|
|
c714720578 | ||
|
|
281fc939ac | ||
|
|
633bef2ac5 | ||
|
|
a8357e7644 |
@@ -103,62 +103,104 @@ void nextLevel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(percent) {
|
void setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
parent.setLevel(this, percent)
|
if (verifyPercent(percent)) {
|
||||||
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
|
parent.setLevel(this, percent)
|
||||||
|
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
|
||||||
|
sendEvent(name: "switch", value: "on")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSaturation(percent) {
|
void setSaturation(percent) {
|
||||||
log.debug "Executing 'setSaturation'"
|
log.debug "Executing 'setSaturation'"
|
||||||
parent.setSaturation(this, percent)
|
if (verifyPercent(percent)) {
|
||||||
sendEvent(name: "saturation", value: percent, displayed: false)
|
parent.setSaturation(this, percent)
|
||||||
|
sendEvent(name: "saturation", value: percent, displayed: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHue(percent) {
|
void setHue(percent) {
|
||||||
log.debug "Executing 'setHue'"
|
log.debug "Executing 'setHue'"
|
||||||
parent.setHue(this, percent)
|
if (verifyPercent(percent)) {
|
||||||
sendEvent(name: "hue", value: percent, displayed: false)
|
parent.setHue(this, percent)
|
||||||
|
sendEvent(name: "hue", value: percent, displayed: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColor(value) {
|
void setColor(value) {
|
||||||
log.debug "setColor: ${value}, $this"
|
log.debug "setColor: ${value}, $this"
|
||||||
parent.setColor(this, value)
|
def events = []
|
||||||
if (value.hue) { sendEvent(name: "hue", value: value.hue, displayed: false)}
|
def validValues = [:]
|
||||||
if (value.saturation) { sendEvent(name: "saturation", value: value.saturation, displayed: false)}
|
|
||||||
if (value.hex) { sendEvent(name: "color", value: value.hex)}
|
if (verifyPercent(value.hue)) {
|
||||||
if (value.level) { sendEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")}
|
events << createEvent(name: "hue", value: value.hue, displayed: false)
|
||||||
sendEvent(name: "switch", value: "on")
|
validValues.hue = value.hue
|
||||||
|
}
|
||||||
|
if (verifyPercent(value.saturation)) {
|
||||||
|
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
|
||||||
|
validValues.saturation = value.saturation
|
||||||
|
}
|
||||||
|
if (value.hex != null) {
|
||||||
|
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
|
||||||
|
events << createEvent(name: "color", value: value.hex)
|
||||||
|
validValues.hex = value.hex
|
||||||
|
} else {
|
||||||
|
log.warn "$value.hex is not a valid color"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (verifyPercent(value.level)) {
|
||||||
|
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
|
||||||
|
validValues.level = value.level
|
||||||
|
}
|
||||||
|
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
|
||||||
|
events << createEvent(name: "switch", value: "off")
|
||||||
|
validValues.switch = "off"
|
||||||
|
} else {
|
||||||
|
events << createEvent(name: "switch", value: "on")
|
||||||
|
validValues.switch = "on"
|
||||||
|
}
|
||||||
|
if (!events.isEmpty()) {
|
||||||
|
parent.setColor(this, validValues)
|
||||||
|
}
|
||||||
|
events.each {
|
||||||
|
sendEvent(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
log.debug "Executing 'reset'"
|
log.debug "Executing 'reset'"
|
||||||
def value = [level:100, saturation:56, hue:23]
|
def value = [level:100, saturation:56, hue:23]
|
||||||
setAdjustedColor(value)
|
setAdjustedColor(value)
|
||||||
parent.poll()
|
parent.poll()
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAdjustedColor(value) {
|
void setAdjustedColor(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setAdjustedColor: ${value}"
|
log.trace "setAdjustedColor: ${value}"
|
||||||
def adjusted = value + [:]
|
def adjusted = value + [:]
|
||||||
adjusted.hue = adjustOutgoingHue(value.hue)
|
adjusted.hue = adjustOutgoingHue(value.hue)
|
||||||
// Needed because color picker always sends 100
|
// Needed because color picker always sends 100
|
||||||
adjusted.level = null
|
adjusted.level = null
|
||||||
setColor(adjusted)
|
setColor(adjusted)
|
||||||
|
} else {
|
||||||
|
log.warn "Invalid color input"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setColorTemperature(value) {
|
void setColorTemperature(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
log.trace "setColorTemperature: ${value}k"
|
log.trace "setColorTemperature: ${value}k"
|
||||||
parent.setColorTemperature(this, value)
|
parent.setColorTemperature(this, value)
|
||||||
sendEvent(name: "colorTemperature", value: value)
|
sendEvent(name: "colorTemperature", value: value)
|
||||||
}
|
sendEvent(name: "switch", value: "on")
|
||||||
|
} else {
|
||||||
|
log.warn "Invalid color temperature"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh() {
|
void refresh() {
|
||||||
log.debug "Executing 'refresh'"
|
log.debug "Executing 'refresh'"
|
||||||
parent.manualRefresh()
|
parent.manualRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
def adjustOutgoingHue(percent) {
|
def adjustOutgoingHue(percent) {
|
||||||
@@ -177,3 +219,14 @@ def adjustOutgoingHue(percent) {
|
|||||||
log.info "percent: $percent, adjusted: $adjusted"
|
log.info "percent: $percent, adjusted: $adjusted"
|
||||||
adjusted
|
adjusted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def verifyPercent(percent) {
|
||||||
|
if (percent == null)
|
||||||
|
return false
|
||||||
|
else if (percent >= 0 && percent <= 100) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
log.warn "$percent is not 0-100"
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,8 +79,12 @@ void off() {
|
|||||||
|
|
||||||
void setLevel(percent) {
|
void setLevel(percent) {
|
||||||
log.debug "Executing 'setLevel'"
|
log.debug "Executing 'setLevel'"
|
||||||
parent.setLevel(this, percent)
|
if (percent != null && percent >= 0 && percent <= 100) {
|
||||||
sendEvent(name: "level", value: percent)
|
parent.setLevel(this, percent)
|
||||||
|
sendEvent(name: "level", value: percent)
|
||||||
|
} else {
|
||||||
|
log.warn "$percent is not 0-100"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh() {
|
void refresh() {
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ private List parseContactMessage(String description) {
|
|||||||
parts.each { part ->
|
parts.each { part ->
|
||||||
part = part.trim()
|
part = part.trim()
|
||||||
if (part.startsWith('contactState:')) {
|
if (part.startsWith('contactState:')) {
|
||||||
results << getContactResult(part, description)
|
results.addAll(getContactResult(part, description))
|
||||||
}
|
}
|
||||||
else if (part.startsWith('accelerationState:')) {
|
else if (part.startsWith('accelerationState:')) {
|
||||||
results << getAccelerationResult(part, description)
|
results << getAccelerationResult(part, description)
|
||||||
@@ -316,7 +316,7 @@ private List getContactResult(part, description) {
|
|||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
private getAccelerationResult(part, description) {
|
private Map getAccelerationResult(part, description) {
|
||||||
def name = "acceleration"
|
def name = "acceleration"
|
||||||
def value = part.endsWith("1") ? "active" : "inactive"
|
def value = part.endsWith("1") ? "active" : "inactive"
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
@@ -335,7 +335,7 @@ private getAccelerationResult(part, description) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTempResult(part, description) {
|
private Map getTempResult(part, description) {
|
||||||
def name = "temperature"
|
def name = "temperature"
|
||||||
def temperatureScale = getTemperatureScale()
|
def temperatureScale = getTemperatureScale()
|
||||||
def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale)
|
def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale)
|
||||||
@@ -360,7 +360,7 @@ private getTempResult(part, description) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private getXyzResult(results, description) {
|
private Map getXyzResult(results, description) {
|
||||||
def name = "threeAxis"
|
def name = "threeAxis"
|
||||||
def value = "${results.x},${results.y},${results.z}"
|
def value = "${results.x},${results.y},${results.z}"
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
@@ -379,7 +379,7 @@ private getXyzResult(results, description) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private getBatteryResult(part, description) {
|
private Map getBatteryResult(part, description) {
|
||||||
def batteryDivisor = description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"} ? description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"}.split(":")[1].trim() : null
|
def batteryDivisor = description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"} ? description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"}.split(":")[1].trim() : null
|
||||||
def name = "battery"
|
def name = "battery"
|
||||||
def value = zigbee.parseSmartThingsBatteryValue(part, batteryDivisor)
|
def value = zigbee.parseSmartThingsBatteryValue(part, batteryDivisor)
|
||||||
@@ -400,7 +400,7 @@ private getBatteryResult(part, description) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
private getRssiResult(part, description, lastHop=false) {
|
private Map getRssiResult(part, description, lastHop=false) {
|
||||||
def name = lastHop ? "lastHopRssi" : "rssi"
|
def name = lastHop ? "lastHopRssi" : "rssi"
|
||||||
def valueString = part.split(":")[1].trim()
|
def valueString = part.split(":")[1].trim()
|
||||||
def value = (Integer.parseInt(valueString) - 128).toString()
|
def value = (Integer.parseInt(valueString) - 128).toString()
|
||||||
@@ -431,7 +431,7 @@ private getRssiResult(part, description, lastHop=false) {
|
|||||||
* Note: To make the signal strength indicator more accurate, we could combine
|
* Note: To make the signal strength indicator more accurate, we could combine
|
||||||
* LQI with RSSI.
|
* LQI with RSSI.
|
||||||
*/
|
*/
|
||||||
private getLqiResult(part, description, lastHop=false) {
|
private Map getLqiResult(part, description, lastHop=false) {
|
||||||
def name = lastHop ? "lastHopLqi" : "lqi"
|
def name = lastHop ? "lastHopLqi" : "lqi"
|
||||||
def valueString = part.split(":")[1].trim()
|
def valueString = part.split(":")[1].trim()
|
||||||
def percentageOf = 255
|
def percentageOf = 255
|
||||||
|
|||||||
@@ -56,21 +56,17 @@ metadata {
|
|||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "description is $description"
|
log.debug "description is $description"
|
||||||
|
|
||||||
def resultMap = zigbee.getKnownDescription(description)
|
def event = zigbee.getEvent(description)
|
||||||
if (resultMap) {
|
if (event) {
|
||||||
log.info resultMap
|
log.info event
|
||||||
if (resultMap.type == "update") {
|
if (event.name == "power") {
|
||||||
log.info "$device updates: ${resultMap.value}"
|
|
||||||
}
|
|
||||||
else if (resultMap.type == "power") {
|
|
||||||
def powerValue
|
|
||||||
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
|
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
|
||||||
powerValue = (resultMap.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
|
event.value = (event.value as Integer) / 10 //TODO: The divisor value needs to be set as part of configuration
|
||||||
sendEvent(name: "power", value: powerValue)
|
sendEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendEvent(name: resultMap.type, value: resultMap.value)
|
sendEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -51,15 +51,9 @@ metadata {
|
|||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "description is $description"
|
log.debug "description is $description"
|
||||||
|
|
||||||
def resultMap = zigbee.getKnownDescription(description)
|
def event = zigbee.getEvent(description)
|
||||||
if (resultMap) {
|
if (event) {
|
||||||
log.info resultMap
|
sendEvent(event)
|
||||||
if (resultMap.type == "update") {
|
|
||||||
log.info "$device updates: ${resultMap.value}"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(name: resultMap.type, value: resultMap.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||||
|
|||||||
@@ -83,32 +83,19 @@ def uninstalled() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
/*
|
|
||||||
def cmds =
|
def cmds =
|
||||||
zigbee.configSetup("${CLUSTER_DOORLOCK}", "${DOORLOCK_ATTR_LOCKSTATE}",
|
zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE,
|
||||||
"${TYPE_ENUM8}", 0, 3600, "{01}") +
|
TYPE_ENUM8, 0, 3600, null) +
|
||||||
zigbee.configSetup("${CLUSTER_POWER}", "${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING}",
|
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING,
|
||||||
"${TYPE_U8}", 600, 21600, "{01}")
|
TYPE_U8, 600, 21600, 0x01)
|
||||||
*/
|
|
||||||
def zigbeeId = device.zigbeeId
|
|
||||||
def cmds =
|
|
||||||
[
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 1 ${CLUSTER_DOORLOCK} {$zigbeeId} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report ${CLUSTER_DOORLOCK} ${DOORLOCK_ATTR_LOCKSTATE} ${TYPE_ENUM8} 0 3600 {01}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 0x${device.endpointId}", "delay 200",
|
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 1 ${CLUSTER_POWER} {$zigbeeId} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report ${CLUSTER_POWER} ${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING} ${TYPE_U8} 600 21600 {01}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 0x${device.endpointId}", "delay 200",
|
|
||||||
]
|
|
||||||
log.info "configure() --- cmds: $cmds"
|
log.info "configure() --- cmds: $cmds"
|
||||||
return cmds + refresh() // send refresh cmds as part of config
|
return cmds + refresh() // send refresh cmds as part of config
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
def cmds =
|
def cmds =
|
||||||
zigbee.refreshData("${CLUSTER_DOORLOCK}", "${DOORLOCK_ATTR_LOCKSTATE}") +
|
zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE) +
|
||||||
zigbee.refreshData("${CLUSTER_POWER}", "${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING}")
|
zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING)
|
||||||
log.info "refresh() --- cmds: $cmds"
|
log.info "refresh() --- cmds: $cmds"
|
||||||
return cmds
|
return cmds
|
||||||
}
|
}
|
||||||
@@ -121,34 +108,27 @@ def parse(String description) {
|
|||||||
map = parseReportAttributeMessage(description)
|
map = parseReportAttributeMessage(description)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug "parse() --- Parse returned $map"
|
|
||||||
def result = map ? createEvent(map) : null
|
def result = map ? createEvent(map) : null
|
||||||
|
log.debug "parse() --- returned: $result"
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock capability commands
|
// Lock capability commands
|
||||||
def lock() {
|
def lock() {
|
||||||
//def cmds = zigbee.zigbeeCommand("${CLUSTER_DOORLOCK}", "${DOORLOCK_CMD_LOCK_DOOR}", "{}")
|
def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_LOCK_DOOR)
|
||||||
//log.info "lock() -- cmds: $cmds"
|
log.info "lock() -- cmds: $cmds"
|
||||||
//return cmds
|
return cmds
|
||||||
"st cmd 0x${device.deviceNetworkId} 0x${device.endpointId} ${CLUSTER_DOORLOCK} ${DOORLOCK_CMD_LOCK_DOOR} {}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def unlock() {
|
def unlock() {
|
||||||
//def cmds = zigbee.zigbeeCommand("${CLUSTER_DOORLOCK}", "${DOORLOCK_CMD_UNLOCK_DOOR}", "{}")
|
def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_UNLOCK_DOOR)
|
||||||
//log.info "unlock() -- cmds: $cmds"
|
log.info "unlock() -- cmds: $cmds"
|
||||||
//return cmds
|
return cmds
|
||||||
"st cmd 0x${device.deviceNetworkId} 0x${device.endpointId} ${CLUSTER_DOORLOCK} ${DOORLOCK_CMD_UNLOCK_DOOR} {}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private methods
|
// Private methods
|
||||||
private Map parseReportAttributeMessage(String description) {
|
private Map parseReportAttributeMessage(String description) {
|
||||||
log.trace "parseReportAttributeMessage() --- description: $description"
|
|
||||||
|
|
||||||
Map descMap = zigbee.parseDescriptionAsMap(description)
|
Map descMap = zigbee.parseDescriptionAsMap(description)
|
||||||
|
|
||||||
log.debug "parseReportAttributeMessage() --- descMap: $descMap"
|
|
||||||
|
|
||||||
Map resultMap = [:]
|
Map resultMap = [:]
|
||||||
if (descMap.clusterInt == CLUSTER_POWER && descMap.attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) {
|
if (descMap.clusterInt == CLUSTER_POWER && descMap.attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) {
|
||||||
resultMap.name = "battery"
|
resultMap.name = "battery"
|
||||||
@@ -156,18 +136,24 @@ private Map parseReportAttributeMessage(String description) {
|
|||||||
if (device.getDataValue("manufacturer") == "Yale") { //Handling issue with Yale locks incorrect battery reporting
|
if (device.getDataValue("manufacturer") == "Yale") { //Handling issue with Yale locks incorrect battery reporting
|
||||||
resultMap.value = Integer.parseInt(descMap.value, 16)
|
resultMap.value = Integer.parseInt(descMap.value, 16)
|
||||||
}
|
}
|
||||||
log.info "parseReportAttributeMessage() --- battery: ${resultMap.value}"
|
|
||||||
}
|
}
|
||||||
else if (descMap.clusterInt == CLUSTER_DOORLOCK && descMap.attrInt == DOORLOCK_ATTR_LOCKSTATE) {
|
else if (descMap.clusterInt == CLUSTER_DOORLOCK && descMap.attrInt == DOORLOCK_ATTR_LOCKSTATE) {
|
||||||
def value = Integer.parseInt(descMap.value, 16)
|
def value = Integer.parseInt(descMap.value, 16)
|
||||||
|
def linkText = getLinkText(device)
|
||||||
resultMap.name = "lock"
|
resultMap.name = "lock"
|
||||||
resultMap.putAll([0:["value":"unknown",
|
if (value == 0) {
|
||||||
"descriptionText":"Not fully locked"],
|
resultMap.value = "unknown"
|
||||||
1:["value":"locked"],
|
resultMap.descriptionText = "${linkText} is not fully locked"
|
||||||
2:["value":"unlocked"]].get(value,
|
} else if (value == 1) {
|
||||||
["value":"unknown",
|
resultMap.value = "locked"
|
||||||
"descriptionText":"Unknown lock state"]))
|
resultMap.descriptionText = "${linkText} is locked"
|
||||||
log.info "parseReportAttributeMessage() --- lock: ${resultMap.value}"
|
} else if (value == 2) {
|
||||||
|
resultMap.value = "unlocked"
|
||||||
|
resultMap.descriptionText = "${linkText} is unlocked"
|
||||||
|
} else {
|
||||||
|
resultMap.value = "unknown"
|
||||||
|
resultMap.descriptionText = "${linkText} is in unknown lock state"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.debug "parseReportAttributeMessage() --- ignoring attribute"
|
log.debug "parseReportAttributeMessage() --- ignoring attribute"
|
||||||
|
|||||||
@@ -51,22 +51,15 @@ metadata {
|
|||||||
// Parse incoming device messages to generate events
|
// Parse incoming device messages to generate events
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "description is $description"
|
log.debug "description is $description"
|
||||||
|
def event = zigbee.getEvent(description)
|
||||||
def resultMap = zigbee.getKnownDescription(description)
|
if (event) {
|
||||||
if (resultMap) {
|
if (event.name == "power") {
|
||||||
log.info resultMap
|
|
||||||
if (resultMap.type == "update") {
|
|
||||||
log.info "$device updates: ${resultMap.value}"
|
|
||||||
}
|
|
||||||
else if (resultMap.type == "power") {
|
|
||||||
def powerValue
|
def powerValue
|
||||||
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
|
powerValue = (event.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
|
||||||
powerValue = (resultMap.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
|
sendEvent(name: "power", value: powerValue)
|
||||||
sendEvent(name: "power", value: powerValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendEvent(name: resultMap.type, value: resultMap.value)
|
sendEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -53,16 +53,9 @@ metadata {
|
|||||||
// Parse incoming device messages to generate events
|
// Parse incoming device messages to generate events
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "description is $description"
|
log.debug "description is $description"
|
||||||
|
def event = zigbee.getEvent(description)
|
||||||
def resultMap = zigbee.getKnownDescription(description)
|
if (event) {
|
||||||
if (resultMap) {
|
sendEvent(event)
|
||||||
log.info resultMap
|
|
||||||
if (resultMap.type == "update") {
|
|
||||||
log.info "$device updates: ${resultMap.value}"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(name: resultMap.type, value: resultMap.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||||
|
|||||||
@@ -73,16 +73,9 @@ metadata {
|
|||||||
// Parse incoming device messages to generate events
|
// Parse incoming device messages to generate events
|
||||||
def parse(String description) {
|
def parse(String description) {
|
||||||
log.debug "description is $description"
|
log.debug "description is $description"
|
||||||
|
def event = zigbee.getEvent(description)
|
||||||
def finalResult = zigbee.getKnownDescription(description)
|
if (event) {
|
||||||
if (finalResult) {
|
sendEvent(event)
|
||||||
log.info finalResult
|
|
||||||
if (finalResult.type == "update") {
|
|
||||||
log.info "$device updates: ${finalResult.value}"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sendEvent(name: finalResult.type, value: finalResult.value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||||
|
|||||||
@@ -87,13 +87,10 @@ def authPage(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
def installed() {
|
def installed() {
|
||||||
log.debug "Installed with settings: ${settings}"
|
|
||||||
initialize()
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
log.debug "Updated with settings: ${settings}"
|
|
||||||
unsubscribe()
|
|
||||||
initialize()
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,72 +103,24 @@ def uninstalled() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def initialize() {
|
def initialize() {
|
||||||
atomicState.attached_sensors = [:]
|
unsubscribe()
|
||||||
if (plantlinksensors){
|
if (plantlinksensors){
|
||||||
subscribe(plantlinksensors, "moisture_status", moistureHandler)
|
|
||||||
subscribe(plantlinksensors, "battery_status", batteryHandler)
|
|
||||||
plantlinksensors.each{ sensor_device ->
|
plantlinksensors.each{ sensor_device ->
|
||||||
sensor_device.setStatusIcon("Waiting on First Measurement")
|
subscribe(sensor_device, "moisture_status", moistureHandler)
|
||||||
|
subscribe(sensor_device, "battery_status", batteryHandler)
|
||||||
sensor_device.setInstallSmartApp("connectedToSmartApp")
|
sensor_device.setInstallSmartApp("connectedToSmartApp")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def dock_sensor(device_serial, expected_plant_name) {
|
def updatePlantNameIfNeeded(plant, expected_plant_name){
|
||||||
def docking_body_json_builder = new JsonBuilder([version: '1c', smartthings_device_id: device_serial])
|
|
||||||
def docking_params = [
|
|
||||||
uri : appSettings.https_plantLinkServer,
|
|
||||||
path : "/api/v1/smartthings/links",
|
|
||||||
headers : ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
|
||||||
contentType: "application/json",
|
|
||||||
body: docking_body_json_builder.toString()
|
|
||||||
]
|
|
||||||
def plant_post_body_map = [
|
|
||||||
plant_type_key: 999999,
|
|
||||||
soil_type_key : 1000004
|
|
||||||
]
|
|
||||||
def plant_post_params = [
|
|
||||||
uri : appSettings.https_plantLinkServer,
|
|
||||||
path : "/api/v1/plants",
|
|
||||||
headers : ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
|
||||||
contentType: "application/json",
|
|
||||||
]
|
|
||||||
log.debug "Creating new plant on myplantlink.com - ${expected_plant_name}"
|
|
||||||
httpPost(docking_params) { docking_response ->
|
|
||||||
if (parse_api_response(docking_response, "Docking a link")) {
|
|
||||||
if (docking_response.data.plants.size() == 0) {
|
|
||||||
log.debug "creating plant for - ${expected_plant_name}"
|
|
||||||
plant_post_body_map["name"] = expected_plant_name
|
|
||||||
plant_post_body_map['links_key'] = [docking_response.data.key]
|
|
||||||
def plant_post_body_json_builder = new JsonBuilder(plant_post_body_map)
|
|
||||||
plant_post_params["body"] = plant_post_body_json_builder.toString()
|
|
||||||
httpPost(plant_post_params) { plant_post_response ->
|
|
||||||
if(parse_api_response(plant_post_response, 'creating plant')){
|
|
||||||
def attached_map = atomicState.attached_sensors
|
|
||||||
attached_map[device_serial] = plant_post_response.data
|
|
||||||
atomicState.attached_sensors = attached_map
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
def plant = docking_response.data.plants[0]
|
|
||||||
def attached_map = atomicState.attached_sensors
|
|
||||||
attached_map[device_serial] = plant
|
|
||||||
atomicState.attached_sensors = attached_map
|
|
||||||
checkAndUpdatePlantIfNeeded(plant, expected_plant_name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
def checkAndUpdatePlantIfNeeded(plant, expected_plant_name){
|
|
||||||
def plant_put_params = [
|
def plant_put_params = [
|
||||||
uri : appSettings.https_plantLinkServer,
|
uri : appSettings.https_plantLinkServer,
|
||||||
headers : ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
headers : ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
||||||
contentType : "application/json"
|
contentType : "application/json"
|
||||||
]
|
]
|
||||||
if (plant.name != expected_plant_name) {
|
if (plant.name != expected_plant_name) {
|
||||||
log.debug "updating plant for - ${expected_plant_name}"
|
log.debug "renaming plant ${plant.key} - ${expected_plant_name}"
|
||||||
plant_put_params["path"] = "/api/v1/plants/${plant.key}"
|
plant_put_params["path"] = "/api/v1/plants/${plant.key}"
|
||||||
def plant_put_body_map = [
|
def plant_put_body_map = [
|
||||||
name: expected_plant_name
|
name: expected_plant_name
|
||||||
@@ -185,32 +134,39 @@ def checkAndUpdatePlantIfNeeded(plant, expected_plant_name){
|
|||||||
}
|
}
|
||||||
|
|
||||||
def moistureHandler(event){
|
def moistureHandler(event){
|
||||||
def expected_plant_name = "SmartThings - ${event.displayName}"
|
log.debug "moistureHandler - ${event.value}"
|
||||||
def device_serial = getDeviceSerialFromEvent(event)
|
|
||||||
|
|
||||||
if (!atomicState.attached_sensors.containsKey(device_serial)){
|
def expected_plant_name = "${event.displayName} (ST)"
|
||||||
dock_sensor(device_serial, expected_plant_name)
|
def device_serial = getDeviceSerialFromEvent(event)
|
||||||
|
def device_battery = atomicState["battery${device_serial}"]
|
||||||
|
if ( device_battery == null){
|
||||||
|
log.error "Missing Battery Voltage - next cycle should have it"
|
||||||
}else{
|
}else{
|
||||||
|
// {"type":"link","signal":"0x00","zigbeedeviceid":"0022A3000003D75A","created":1458843686,"moisture":"0x1987"}
|
||||||
|
def appendedEventWithBatteryInfo = event.value.replace('}',",\"battery\":\"${device_battery}\"}")
|
||||||
|
log.debug "payload - ${appendedEventWithBatteryInfo}"
|
||||||
def measurement_post_params = [
|
def measurement_post_params = [
|
||||||
uri: appSettings.https_plantLinkServer,
|
uri: appSettings.https_plantLinkServer,
|
||||||
path: "/api/v1/smartthings/links/${device_serial}/measurements",
|
path: "/api/v1/smartthings/links/${device_serial}/measurements",
|
||||||
headers: ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
headers: ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
body: event.value
|
body: appendedEventWithBatteryInfo
|
||||||
]
|
]
|
||||||
|
|
||||||
httpPost(measurement_post_params) { measurement_post_response ->
|
httpPost(measurement_post_params) { measurement_post_response ->
|
||||||
if (parse_api_response(measurement_post_response, 'creating moisture measurement') &&
|
if (parse_api_response(measurement_post_response, 'creating moisture measurement') && measurement_post_response.data.size() >0){
|
||||||
measurement_post_response.data.size() >0){
|
|
||||||
def measurement = measurement_post_response.data[0]
|
def measurement = measurement_post_response.data[0]
|
||||||
def plant = measurement.plant
|
def plant = measurement.plant
|
||||||
log.debug plant
|
|
||||||
checkAndUpdatePlantIfNeeded(plant, expected_plant_name)
|
updatePlantNameIfNeeded(plant, expected_plant_name)
|
||||||
|
|
||||||
plantlinksensors.each{ sensor_device ->
|
plantlinksensors.each{ sensor_device ->
|
||||||
if (sensor_device.id == event.deviceId){
|
if (sensor_device.id == event.deviceId){
|
||||||
sensor_device.setStatusIcon(plant.status)
|
sensor_device.setStatusIcon(plant.status)
|
||||||
if (plant.last_measurements && plant.last_measurements[0].moisture){
|
if (plant.last_measurements && plant.last_measurements[0].moisture){
|
||||||
sensor_device.setPlantFuelLevel(plant.last_measurements[0].moisture * 100 as int)
|
sensor_device.setPlantFuelLevel(plant.last_measurements[0].moisture * 100 as int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plant.last_measurements && plant.last_measurements[0].battery){
|
if (plant.last_measurements && plant.last_measurements[0].battery){
|
||||||
sensor_device.setBatteryLevel(plant.last_measurements[0].battery * 100 as int)
|
sensor_device.setBatteryLevel(plant.last_measurements[0].battery * 100 as int)
|
||||||
}
|
}
|
||||||
@@ -224,21 +180,7 @@ def moistureHandler(event){
|
|||||||
def batteryHandler(event){
|
def batteryHandler(event){
|
||||||
def expected_plant_name = "SmartThings - ${event.displayName}"
|
def expected_plant_name = "SmartThings - ${event.displayName}"
|
||||||
def device_serial = getDeviceSerialFromEvent(event)
|
def device_serial = getDeviceSerialFromEvent(event)
|
||||||
|
atomicState["battery${device_serial}"] = getDeviceBatteryFromEvent(event)
|
||||||
if (!atomicState.attached_sensors.containsKey(device_serial)){
|
|
||||||
dock_sensor(device_serial, expected_plant_name)
|
|
||||||
}else{
|
|
||||||
def measurement_post_params = [
|
|
||||||
uri: appSettings.https_plantLinkServer,
|
|
||||||
path: "/api/v1/smartthings/links/${device_serial}/measurements",
|
|
||||||
headers: ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
|
||||||
contentType: "application/json",
|
|
||||||
body: event.value
|
|
||||||
]
|
|
||||||
httpPost(measurement_post_params) { measurement_post_response ->
|
|
||||||
parse_api_response(measurement_post_response, 'creating battery measurement')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def getDeviceSerialFromEvent(event){
|
def getDeviceSerialFromEvent(event){
|
||||||
@@ -247,6 +189,12 @@ def getDeviceSerialFromEvent(event){
|
|||||||
return match_result[0][1]
|
return match_result[0][1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getDeviceBatteryFromEvent(event){
|
||||||
|
def pattern = /.*"battery"\s*:\s*"(\w+)".*/
|
||||||
|
def match_result = (event.value =~ pattern)
|
||||||
|
return match_result[0][1]
|
||||||
|
}
|
||||||
|
|
||||||
def oauthInitUrl(){
|
def oauthInitUrl(){
|
||||||
atomicState.oauthInitState = UUID.randomUUID().toString()
|
atomicState.oauthInitState = UUID.randomUUID().toString()
|
||||||
def oauthParams = [
|
def oauthParams = [
|
||||||
@@ -263,12 +211,13 @@ def buildRedirectUrl(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
def swapToken(){
|
def swapToken(){
|
||||||
|
log.debug "PlantLink Connector - OAuth Token"
|
||||||
def code = params.code
|
def code = params.code
|
||||||
def oauthState = params.state
|
def oauthState = params.state
|
||||||
def stcid = appSettings.client_id
|
def stcid = appSettings.client_id
|
||||||
def postParams = [
|
def postParams = [
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
uri: "https://oso-tech.appspot.com",
|
uri: appSettings.https_plantLinkServer,
|
||||||
path: "/api/v1/oauth-token",
|
path: "/api/v1/oauth-token",
|
||||||
query: [grant_type:'authorization_code', code:params.code, client_id:stcid,
|
query: [grant_type:'authorization_code', code:params.code, client_id:stcid,
|
||||||
client_secret:appSettings.client_secret, redirect_uri: buildRedirectUrl()],
|
client_secret:appSettings.client_secret, redirect_uri: buildRedirectUrl()],
|
||||||
@@ -321,10 +270,11 @@ def swapToken(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
private refreshAuthToken() {
|
private refreshAuthToken() {
|
||||||
|
log.debug "PlantLink Connector - Refresh OAuth"
|
||||||
def stcid = appSettings.client_id
|
def stcid = appSettings.client_id
|
||||||
def refreshParams = [
|
def refreshParams = [
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
uri: "https://hardware-dot-oso-tech.appspot.com",
|
uri: appSettings.https_plantLinkServer,
|
||||||
path: "/api/v1/oauth-token",
|
path: "/api/v1/oauth-token",
|
||||||
query: [grant_type:'refresh_token', code:"${atomicState.refreshToken}", client_id:stcid,
|
query: [grant_type:'refresh_token', code:"${atomicState.refreshToken}", client_id:stcid,
|
||||||
client_secret:appSettings.client_secret],
|
client_secret:appSettings.client_secret],
|
||||||
@@ -333,7 +283,6 @@ private refreshAuthToken() {
|
|||||||
def jsonMap
|
def jsonMap
|
||||||
httpPost(refreshParams) { resp ->
|
httpPost(refreshParams) { resp ->
|
||||||
if(resp.status == 200){
|
if(resp.status == 200){
|
||||||
log.debug "OAuth Token refreshed"
|
|
||||||
jsonMap = resp.data
|
jsonMap = resp.data
|
||||||
if (resp.data) {
|
if (resp.data) {
|
||||||
atomicState.refreshToken = resp?.data?.refresh_token
|
atomicState.refreshToken = resp?.data?.refresh_token
|
||||||
@@ -346,12 +295,12 @@ private refreshAuthToken() {
|
|||||||
}
|
}
|
||||||
data.action = ""
|
data.action = ""
|
||||||
}else{
|
}else{
|
||||||
log.debug "refresh failed ${resp.status} : ${resp.status.code}"
|
log.debug "PlantLink Server - ${resp.status} : ${resp.status.code}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception e){
|
catch(Exception e){
|
||||||
log.debug "caught exception refreshing auth token: " + e
|
log.debug "PlantLink Connector - OAuth Refresh Failed: " + e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,7 +313,7 @@ def parse_api_response(resp, message) {
|
|||||||
refreshAuthToken()
|
refreshAuthToken()
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
debugEvent("Authentication error, invalid authentication method, lack of credentials, etc.", true)
|
debugEvent("Plantlink Error: ${resp.status} - ${resp.status.code}", true)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ private sendDeveloperReq() {
|
|||||||
headers: [
|
headers: [
|
||||||
HOST: host
|
HOST: host
|
||||||
],
|
],
|
||||||
body: [devicetype: "$token-0", username: "$token-0"]], "${selectedHue}"))
|
body: [devicetype: "$token-0"]], "${selectedHue}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
private discoverHueBulbs() {
|
private discoverHueBulbs() {
|
||||||
@@ -657,39 +657,53 @@ def setColorTemperature(childDevice, huesettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def setColor(childDevice, huesettings) {
|
def setColor(childDevice, huesettings) {
|
||||||
log.debug "Executing 'setColor($huesettings)'"
|
log.debug "Executing 'setColor($huesettings)'"
|
||||||
|
|
||||||
|
def value = [:]
|
||||||
def hue = null
|
def hue = null
|
||||||
def sat = null
|
def sat = null
|
||||||
def xy = null
|
def xy = null
|
||||||
if (huesettings.hex) {
|
|
||||||
xy = getHextoXY(huesettings.hex)
|
if (huesettings.hex != null) {
|
||||||
} else if (huesettings.hue && huesettings.saturation) {
|
value.xy = getHextoXY(huesettings.hex)
|
||||||
hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
|
} else {
|
||||||
sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
|
if (huesettings.hue != null)
|
||||||
|
value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
|
||||||
|
if (huesettings.saturation != null)
|
||||||
|
value.sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
|
||||||
}
|
}
|
||||||
def alert = huesettings.alert ? huesettings.alert : "none"
|
|
||||||
def transition = huesettings.transition ? huesettings.transition : 4
|
// Default behavior is to turn light on
|
||||||
|
value.on = true
|
||||||
|
|
||||||
def value = [xy: xy, sat: sat, hue: hue, alert: alert, transitiontime: transition, on: true]
|
if (huesettings.level != null) {
|
||||||
|
if (huesettings.level <= 0)
|
||||||
|
value.on = false
|
||||||
|
else if (huesettings.level == 1)
|
||||||
|
value.bri = 1
|
||||||
|
else
|
||||||
|
value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
|
||||||
|
}
|
||||||
|
value.alert = huesettings.alert ? huesettings.alert : "none"
|
||||||
|
value.transition = huesettings.transition ? huesettings.transition : 4
|
||||||
|
|
||||||
if (huesettings.level != null) {
|
// Make sure to turn off light if requested
|
||||||
if (huesettings.level == 1) value.bri = 1 else value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
|
if (huesettings.switch == "off")
|
||||||
value.on = value.bri > 0
|
value.on = false
|
||||||
}
|
|
||||||
|
|
||||||
log.debug "sending command $value"
|
log.debug "sending command $value"
|
||||||
put("lights/${getId(childDevice)}/state", value)
|
put("lights/${getId(childDevice)}/state", value)
|
||||||
|
return "Color set to $value"
|
||||||
}
|
}
|
||||||
|
|
||||||
def nextLevel(childDevice) {
|
def nextLevel(childDevice) {
|
||||||
def level = device.latestValue("level") as Integer ?: 0
|
def level = device.latestValue("level") as Integer ?: 0
|
||||||
if (level < 100) {
|
if (level < 100) {
|
||||||
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
||||||
}
|
} else {
|
||||||
else {
|
level = 25
|
||||||
level = 25
|
}
|
||||||
}
|
setLevel(childDevice,level)
|
||||||
setLevel(childDevice,level)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getId(childDevice) {
|
private getId(childDevice) {
|
||||||
@@ -788,16 +802,14 @@ private getHextoXY(String colorStr) {
|
|||||||
|
|
||||||
// Make green more vivid
|
// Make green more vivid
|
||||||
if (normalizedToOne[1] > 0.04045) {
|
if (normalizedToOne[1] > 0.04045) {
|
||||||
green = (float) Math.pow((normalizedToOne[1] + 0.055)
|
green = (float) Math.pow((normalizedToOne[1] + 0.055) / (1.0 + 0.055), 2.4);
|
||||||
/ (1.0 + 0.055), 2.4);
|
|
||||||
} else {
|
} else {
|
||||||
green = (float) (normalizedToOne[1] / 12.92);
|
green = (float) (normalizedToOne[1] / 12.92);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make blue more vivid
|
// Make blue more vivid
|
||||||
if (normalizedToOne[2] > 0.04045) {
|
if (normalizedToOne[2] > 0.04045) {
|
||||||
blue = (float) Math.pow((normalizedToOne[2] + 0.055)
|
blue = (float) Math.pow((normalizedToOne[2] + 0.055) / (1.0 + 0.055), 2.4);
|
||||||
/ (1.0 + 0.055), 2.4);
|
|
||||||
} else {
|
} else {
|
||||||
blue = (float) (normalizedToOne[2] / 12.92);
|
blue = (float) (normalizedToOne[2] / 12.92);
|
||||||
}
|
}
|
||||||
@@ -806,8 +818,8 @@ private getHextoXY(String colorStr) {
|
|||||||
float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598);
|
float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598);
|
||||||
float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763);
|
float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763);
|
||||||
|
|
||||||
float x = X / (X + Y + Z);
|
float x = (X != 0 ? X / (X + Y + Z) : 0);
|
||||||
float y = Y / (X + Y + Z);
|
float y = (Y != 0 ? Y / (X + Y + Z) : 0);
|
||||||
|
|
||||||
double[] xy = new double[2];
|
double[] xy = new double[2];
|
||||||
xy[0] = x;
|
xy[0] = x;
|
||||||
|
|||||||
Reference in New Issue
Block a user