mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-19 13:20:53 +00:00
Merge pull request #463 from SmartThingsCommunity/staging
Merging changes into prod from staging
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* EnerTalk Energy Meter
|
||||
*
|
||||
* Copyright 2015 hyeon seok yang
|
||||
*
|
||||
* 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: "EnerTalk Energy Meter", namespace: "Encored Technologies", author: "hyeon seok yang") {
|
||||
}
|
||||
|
||||
simulator {
|
||||
// TODO: define status and reply messages here
|
||||
}
|
||||
|
||||
tiles(scale:2) {
|
||||
valueTile("view", "device.view", decoration: "flat") {
|
||||
state "view", label:' ${currentValue} kWh'
|
||||
}
|
||||
valueTile("month", "device.month", width: 6, height : 3, decoration: "flat") {
|
||||
state "month", label:' ${currentValue}'
|
||||
}
|
||||
valueTile("real", "device.real", width: 2, height : 2, decoration: "flat") {
|
||||
state "real", label:' ${currentValue}'
|
||||
}
|
||||
valueTile("tier", "device.tier", width: 2, height : 2, decoration: "flat") {
|
||||
state "tier", label:' ${currentValue}'
|
||||
}
|
||||
valueTile("plan", "device.plan", width: 2, height : 2, decoration: "flat") {
|
||||
state "plan", label:' ${currentValue}'
|
||||
}
|
||||
|
||||
htmlTile(name:"deepLink", action:"linkApp", whitelist:["code.jquery.com",
|
||||
"ajax.googleapis.com",
|
||||
"fonts.googleapis.com",
|
||||
"code.highcharts.com",
|
||||
"enertalk-card.encoredtech.com",
|
||||
"s3-ap-northeast-1.amazonaws.com",
|
||||
"s3.amazonaws.com",
|
||||
"ui-hub.encoredtech.com",
|
||||
"enertalk-auth.encoredtech.com",
|
||||
"api.encoredtech.com",
|
||||
"cdnjs.cloudflare.com",
|
||||
"encoredtech.com",
|
||||
"itunes.apple.com"], width:2, height:2){}
|
||||
|
||||
main (["view"])
|
||||
details (["month", "real", "tier", "plan", "deepLink"])
|
||||
}
|
||||
}
|
||||
|
||||
mappings {
|
||||
|
||||
path("/linkApp") {action: [ GET: "getLinkedApp" ]}
|
||||
}
|
||||
|
||||
def getLinkedApp() {
|
||||
def lang = clientLocale?.language
|
||||
if ("${lang}" == "ko") {
|
||||
lang = "<p style=\'margin-left:15vw; color: #aeaeb0;\'>기기 설정</p>"
|
||||
} else {
|
||||
lang = "<p style=\'margin-left:5vw; color: #aeaeb0;\'>Setup Device</p>"
|
||||
}
|
||||
renderHTML() {
|
||||
head {
|
||||
"""
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, height=device-height">
|
||||
<style>
|
||||
#레이어_1 { margin-left : 17vw; width : 50vw; height : 50vw;}
|
||||
.st0{fill:#B5B6BB;}
|
||||
</style>
|
||||
"""
|
||||
}
|
||||
body {
|
||||
"""
|
||||
<div id="container">
|
||||
<a id="st-deep-link" href="#">
|
||||
<svg version="1.1" id="레이어_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 40 40" style="enable-background:new 0 0 40 40;" xml:space="preserve"><path class="st0" d="M20,0C9,0,0,9,0,20C0,30.5,8,39,18.2,40l3.8-4.8l-3.9-4.8c-4.9-0.9-8.6-5.2-8.6-10.4c0-5.8,4.7-10.5,10.5-10.5
|
||||
S30.5,14.2,30.5,20c0,5.1-3.7,9.4-8.5,10.3l3.7,4.5L21.8,40C32,39.1,40,30.5,40,20C40,9,31,0,20,0z"/></svg>
|
||||
</a>
|
||||
${lang}
|
||||
</div>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script>
|
||||
var ua = navigator.userAgent.toLowerCase();
|
||||
var isAndroid = ua.indexOf("android") > -1;
|
||||
if(!isAndroid) {
|
||||
\$("#st-deep-link").attr("href", "https://itunes.apple.com/kr/app/enertalk-for-home/id1024660780?mt=8");
|
||||
} else {
|
||||
\$("#st-deep-link").attr("href", "market://details?id=com.ionicframework.enertalkhome874425");
|
||||
}
|
||||
</script>
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Copyright 2016 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: "Gentle Wake Up Controller", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Switch"
|
||||
capability "Timed Session"
|
||||
|
||||
attribute "percentComplete", "number"
|
||||
|
||||
command "setPercentComplete", ["number"]
|
||||
}
|
||||
|
||||
simulator {
|
||||
// TODO: define status and reply messages here
|
||||
}
|
||||
|
||||
tiles(scale: 2) {
|
||||
|
||||
multiAttributeTile(name: "richTile", type:"generic", width:6, height:4) {
|
||||
tileAttribute("sessionStatus", key: "PRIMARY_CONTROL") {
|
||||
attributeState "cancelled", action: "timed session.start", icon: "http://f.cl.ly/items/322n181j2K3f281r2s0A/playbutton.png", backgroundColor: "#ffffff", nextState: "running"
|
||||
attributeState "stopped", action: "timed session.start", icon: "http://f.cl.ly/items/322n181j2K3f281r2s0A/playbutton.png", backgroundColor: "#ffffff", nextState: "cancelled"
|
||||
attributeState "running", action: "timed session.stop", icon: "http://f.cl.ly/items/0B3y3p2V3X2l3P3y3W09/stopbutton.png", backgroundColor: "#79b821", nextState: "cancelled"
|
||||
}
|
||||
tileAttribute("timeRemaining", key: "SECONDARY_CONTROL") {
|
||||
attributeState "timeRemaining", label:'${currentValue} remaining'
|
||||
}
|
||||
tileAttribute("percentComplete", key: "SLIDER_CONTROL") {
|
||||
attributeState "percentComplete", action: "timed session.setTimeRemaining"
|
||||
}
|
||||
}
|
||||
|
||||
// start/stop
|
||||
standardTile("sessionStatusTile", "sessionStatus", width: 1, height: 1, canChangeIcon: true) {
|
||||
state "cancelled", label: "Stopped", action: "timed session.start", backgroundColor: "#ffffff", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
||||
state "stopped", label: "Stopped", action: "timed session.start", backgroundColor: "#ffffff", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
||||
state "running", label: "Running", action: "timed session.stop", backgroundColor: "#79b821", icon: "http://f.cl.ly/items/1J1g0H2P0S1G1f2O1s1s/icon.png"
|
||||
}
|
||||
|
||||
// duration
|
||||
valueTile("timeRemainingTile", "timeRemaining", decoration: "flat", width: 2) {
|
||||
state "timeRemaining", label:'${currentValue} left'
|
||||
}
|
||||
controlTile("percentCompleteTile", "percentComplete", "slider", height: 1, width: 3) {
|
||||
state "percentComplete", action: "timed session.setTimeRemaining"
|
||||
}
|
||||
|
||||
main "sessionStatusTile"
|
||||
details "richTile"
|
||||
// details(["richTile", "sessionStatusTile", "timeRemainingTile", "percentCompleteTile"])
|
||||
}
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
def parse(description) {
|
||||
log.debug "Parsing '${description}'"
|
||||
// TODO: handle 'switch' attribute
|
||||
// TODO: handle 'level' attribute
|
||||
// TODO: handle 'sessionStatus' attribute
|
||||
// TODO: handle 'timeRemaining' attribute
|
||||
|
||||
}
|
||||
|
||||
// handle commands
|
||||
def on() {
|
||||
log.debug "Executing 'on'"
|
||||
startDimming()
|
||||
}
|
||||
|
||||
def off() {
|
||||
log.debug "Executing 'off'"
|
||||
stopDimming()
|
||||
}
|
||||
|
||||
def setTimeRemaining(percentComplete) {
|
||||
log.debug "Executing 'setTimeRemaining' to ${percentComplete}% complete"
|
||||
parent.jumpTo(percentComplete)
|
||||
}
|
||||
|
||||
def start() {
|
||||
log.debug "Executing 'start'"
|
||||
startDimming()
|
||||
}
|
||||
|
||||
def stop() {
|
||||
log.debug "Executing 'stop'"
|
||||
stopDimming()
|
||||
}
|
||||
|
||||
def pause() {
|
||||
log.debug "Executing 'pause'"
|
||||
// TODO: handle 'pause' command
|
||||
}
|
||||
|
||||
def cancel() {
|
||||
log.debug "Executing 'cancel'"
|
||||
stopDimming()
|
||||
}
|
||||
|
||||
def startDimming() {
|
||||
log.trace "startDimming"
|
||||
log.debug "parent: ${parent}"
|
||||
parent.start("controller")
|
||||
}
|
||||
|
||||
def stopDimming() {
|
||||
log.trace "stopDimming"
|
||||
log.debug "parent: ${parent}"
|
||||
parent.stop("controller")
|
||||
}
|
||||
|
||||
def controllerEvent(eventData) {
|
||||
log.trace "controllerEvent"
|
||||
sendEvent(eventData)
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
metadata {
|
||||
definition (name: "Timevalve Smart", namespace: "timevalve.gaslock.t-08", author: "ruinnel") {
|
||||
capability "Valve"
|
||||
capability "Refresh"
|
||||
capability "Battery"
|
||||
capability "Temperature Measurement"
|
||||
|
||||
command "setRemaining"
|
||||
command "setTimeout"
|
||||
command "setTimeout10"
|
||||
command "setTimeout20"
|
||||
command "setTimeout30"
|
||||
command "setTimeout40"
|
||||
|
||||
command "remainingLevel"
|
||||
|
||||
attribute "remaining", "number"
|
||||
attribute "remainingText", "String"
|
||||
attribute "timeout", "number"
|
||||
|
||||
//raw desc : 0 0 0x1006 0 0 0 7 0x5E 0x86 0x72 0x5A 0x73 0x98 0x80
|
||||
//fingerprint deviceId:"0x1006", inClusters:"0x5E, 0x86, 0x72, 0x5A, 0x73, 0x98, 0x80"
|
||||
}
|
||||
|
||||
tiles (scale: 2) {
|
||||
multiAttributeTile(name:"statusTile", type:"generic", width:6, height:4) {
|
||||
tileAttribute("device.contact", key: "PRIMARY_CONTROL") {
|
||||
attributeState "open", label: '${name}', action: "close", icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
||||
attributeState "closed", label:'${name}', action: "", icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
||||
}
|
||||
tileAttribute("device.remainingText", key: "SECONDARY_CONTROL") {
|
||||
attributeState "open", label: '${currentValue}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
||||
attributeState "closed", label:'', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
||||
}
|
||||
}
|
||||
|
||||
standardTile("refreshTile", "command.refresh", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
controlTile("remainingSliderTile", "device.remaining", "slider", inactiveLabel: false, range:"(0..590)", height: 2, width: 4) {
|
||||
state "level", action:"remainingLevel"
|
||||
}
|
||||
valueTile("setRemaining", "device.remainingText", inactiveLabel: false, decoration: "flat", height: 2, width: 2){
|
||||
state "remainingText", label:'${currentValue}\nRemaining'//, action: "setRemaining"//, icon: "st.Office.office6"
|
||||
}
|
||||
|
||||
standardTile("setTimeout10", "device.remaining", inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'10Min', action: "setTimeout10", icon:"st.Health & Wellness.health7", defaultState: true
|
||||
state "10", label:'10Min', action: "setTimeout10", icon:"st.Office.office13"
|
||||
}
|
||||
standardTile("setTimeout20", "device.remaining", inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'20Min', action: "setTimeout20", icon:"st.Health & Wellness.health7", defaultState: true
|
||||
state "20", label:'20Min', action: "setTimeout20", icon:"st.Office.office13"
|
||||
}
|
||||
standardTile("setTimeout30", "device.remaining", inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'30Min', action: "setTimeout30", icon:"st.Health & Wellness.health7", defaultState: true
|
||||
state "30", label:'30Min', action: "setTimeout30", icon:"st.Office.office13"
|
||||
}
|
||||
standardTile("setTimeout40", "device.remaining", inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'40Min', action: "setTimeout40", icon:"st.Health & Wellness.health7", defaultState: true
|
||||
state "40", label:'40Min', action: "setTimeout40", icon:"st.Office.office13"
|
||||
}
|
||||
|
||||
valueTile("batteryTile", "device.battery", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
}
|
||||
|
||||
main (["statusTile"])
|
||||
// details (["statusTile", "remainingSliderTile", "setRemaining", "setTimeout10", "setTimeout20", "batteryTile", "refreshTile", "setTimeout30", "setTimeout40"])
|
||||
// details (["statusTile", "batteryTile", "setRemaining", "refreshTile"])
|
||||
details (["statusTile", "batteryTile", "refreshTile"])
|
||||
}
|
||||
}
|
||||
|
||||
def parse(description) {
|
||||
// log.debug "parse - " + description
|
||||
def result = null
|
||||
if (description.startsWith("Err 106")) {
|
||||
state.sec = 0
|
||||
result = createEvent(descriptionText: description, isStateChange: true)
|
||||
} else if (description != "updated") {
|
||||
def cmd = zwave.parse(description, [0x20: 1, 0x25: 1, 0x70: 1, 0x71: 1, 0x98: 1])
|
||||
if (cmd) {
|
||||
log.debug "parsed cmd = " + cmd
|
||||
result = zwaveEvent(cmd)
|
||||
//log.debug("'$description' parsed to $result")
|
||||
} else {
|
||||
log.debug("Couldn't zwave.parse '$description'")
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 복호화 후 zwaveEvent() 호출
|
||||
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
|
||||
//log.debug "SecurityMessageEncapsulation - " + cmd
|
||||
def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x25: 1, 0x70: 1, 0x71: 1, 0x98: 1])
|
||||
if (encapsulatedCommand) {
|
||||
state.sec = 1
|
||||
log.debug "encapsulatedCommand = " + encapsulatedCommand
|
||||
zwaveEvent(encapsulatedCommand)
|
||||
}
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
||||
//log.debug "switch status - " + cmd.value
|
||||
createEvent(name:"contact", value: cmd.value ? "open" : "closed")
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
||||
def map = [ name: "battery", unit: "%" ]
|
||||
if (cmd.batteryLevel == 0xFF) { // Special value for low battery alert
|
||||
map.value = 1
|
||||
map.descriptionText = "${device.displayName} has a low battery"
|
||||
map.isStateChange = true
|
||||
} else {
|
||||
map.value = cmd.batteryLevel
|
||||
}
|
||||
|
||||
log.debug "battery - ${map.value}${map.unit}"
|
||||
// Store time of last battery update so we don't ask every wakeup, see WakeUpNotification handler
|
||||
state.lastbatt = new Date().time
|
||||
createEvent(map)
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||
//log.debug "zwaveEvent - ${device.displayName}: ${cmd}"
|
||||
createEvent(descriptionText: "${device.displayName}: ${cmd}")
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
|
||||
def result = []
|
||||
log.info "zwave.configurationV1.configurationGet - " + cmd
|
||||
def array = cmd.configurationValue
|
||||
def value = ( (array[0] * 0x1000000) + (array[1] * 0x10000) + (array[2] * 0x100) + array[3] ).intdiv(60)
|
||||
if (device.currentValue("contact") == "open") {
|
||||
value = ( (array[0] * 0x1000000) + (array[1] * 0x10000) + (array[2] * 0x100) + array[3] ).intdiv(60)
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
|
||||
if (device.currentValue('contact') == 'open') {
|
||||
def hour = value.intdiv(60);
|
||||
def min = (value % 60).toString().padLeft(2, '0');
|
||||
def text = "${hour}:${min}M"
|
||||
|
||||
log.info "remain - " + text
|
||||
result.add( createEvent(name: "remaining", value: value, displayed: false, isStateChange: true) )
|
||||
result.add( createEvent(name: "remainingText", value: text, displayed: false, isStateChange: true) )
|
||||
} else {
|
||||
result.add( createEvent(name: "timeout", value: value, displayed: false, isStateChange: true) )
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
|
||||
def type = cmd.notificationType
|
||||
if (type == cmd.NOTIFICATION_TYPE_HEAT) {
|
||||
log.info "NotificationReport - ${type}"
|
||||
createEvent(name: "temperature", value: 999, unit: "C", descriptionText: "${device.displayName} is over heat!", displayed: true, isStateChange: true)
|
||||
}
|
||||
}
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
|
||||
def type = cmd.alarmType
|
||||
def level = cmd.alarmLevel
|
||||
|
||||
log.info "AlarmReport - type : ${type}, level : ${level}"
|
||||
def msg = "${device.displayName} is over heat!"
|
||||
def result = createEvent(name: "temperature", value: 999, unit: "C", descriptionText: msg, displayed: true, isStateChange: true)
|
||||
if (sendPushMessage) {
|
||||
sendPushMessage(msg)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// remote open not allow
|
||||
def open() {}
|
||||
|
||||
def close() {
|
||||
// log.debug 'cmd - close()'
|
||||
commands([
|
||||
zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00),
|
||||
zwave.switchBinaryV1.switchBinaryGet()
|
||||
])
|
||||
}
|
||||
|
||||
def setTimeout10() { setTimeout(10) }
|
||||
def setTimeout20() { setTimeout(20) }
|
||||
def setTimeout30() { setTimeout(30) }
|
||||
def setTimeout40() { setTimeout(40) }
|
||||
|
||||
|
||||
def setTimeout(value) {
|
||||
// log.debug "setDefaultTime($value)"
|
||||
commands([
|
||||
zwave.configurationV1.configurationSet(parameterNumber: 0x01, size: 4, scaledConfigurationValue: value * 60),
|
||||
zwave.configurationV1.configurationGet(parameterNumber: 0x01)
|
||||
]);
|
||||
}
|
||||
|
||||
def remainingLevel(value) {
|
||||
// log.debug "remainingLevel($value)"
|
||||
def hour = value.intdiv(60);
|
||||
def min = (value % 60).toString().padLeft(2, '0');
|
||||
def text = "${hour}:${min}M"
|
||||
sendEvent(name: "remaining", value: value, displayed: false, isStateChange: true)
|
||||
sendEvent(name: "remainingText", value: text, displayed: false, isStateChange: true)
|
||||
}
|
||||
|
||||
def setRemaining() {
|
||||
def remaining = device.currentValue("remaining")
|
||||
// log.debug "setConfiguration() - remaining : $remaining"
|
||||
commands([
|
||||
zwave.configurationV1.configurationSet(parameterNumber: 0x03, size: 4, scaledConfigurationValue: remaining * 60),
|
||||
zwave.configurationV1.configurationGet(parameterNumber: 0x03)
|
||||
]);
|
||||
}
|
||||
|
||||
private command(physicalgraph.zwave.Command cmd) {
|
||||
if (state.sec != 0 && !(cmd instanceof physicalgraph.zwave.commands.batteryv1.BatteryGet)) {
|
||||
log.debug "cmd = " + cmd + ", encapsulation"
|
||||
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
|
||||
} else {
|
||||
log.debug "cmd = " + cmd + ", plain"
|
||||
cmd.format()
|
||||
}
|
||||
}
|
||||
|
||||
private commands(commands, delay=200) {
|
||||
delayBetween(commands.collect{ command(it) }, delay)
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
// log.debug 'cmd - refresh()'
|
||||
commands([
|
||||
zwave.batteryV1.batteryGet(),
|
||||
zwave.switchBinaryV1.switchBinaryGet(),
|
||||
zwave.configurationV1.configurationGet(parameterNumber: 0x01),
|
||||
zwave.configurationV1.configurationGet(parameterNumber: 0x03)
|
||||
], 400)
|
||||
}
|
||||
Reference in New Issue
Block a user