mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-09 13:21:53 +00:00
Compare commits
17 Commits
MSA-999-5
...
PROD_2016.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51fb7fc7a9 | ||
|
|
babc0206df | ||
|
|
d419fb8606 | ||
|
|
70aae0d76c | ||
|
|
1cd5c68e68 | ||
|
|
9e427d4108 | ||
|
|
a8628b7343 | ||
|
|
eb8d5ed4c9 | ||
|
|
7b5d618de8 | ||
|
|
c024e09fb8 | ||
|
|
fe92f7ad19 | ||
|
|
ffcacb9da5 | ||
|
|
024a6cb698 | ||
|
|
62a965d90b | ||
|
|
515b268374 | ||
|
|
a103d437c2 | ||
|
|
bdd88deb99 |
@@ -7,9 +7,10 @@ apply plugin: 'smartthings-hipchat'
|
||||
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.3"
|
||||
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.6"
|
||||
}
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
maven {
|
||||
credentials {
|
||||
|
||||
@@ -15,13 +15,13 @@ deployment:
|
||||
develop:
|
||||
branch: master
|
||||
commands:
|
||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3BucketName=$S3_BUCKET_NAME_PREPROD_DEV
|
||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3Buckets="$S3_BUCKETS_DEV"
|
||||
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
||||
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
||||
|
||||
stage:
|
||||
branch: staging
|
||||
commands:
|
||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3BucketName=$S3_BUCKET_NAME_PREPROD_STAGING
|
||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3Buckets="$S3_BUCKETS_STAGE"
|
||||
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
||||
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
||||
|
||||
@@ -28,4 +28,8 @@
|
||||
'''{{ device.displayName }} is On'''.ko={{ device.displayName }}켜졌습니다.
|
||||
'''{{ device.displayName }} is Off'''.ko={{ device.displayName }}꺼졌습니다.
|
||||
'''{{ device.displayName }} power is {{ value }} Watts'''.ko={{ device.displayName }} 전원은 {{ value }}와트입니다
|
||||
'''On'''.ko=켜기
|
||||
'''Off'''.ko=끄기
|
||||
'''Turning On'''.ko=켜기
|
||||
'''Turning Off'''.ko=끄기
|
||||
#==============================================================================
|
||||
|
||||
@@ -65,10 +65,10 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||
attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||
attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||
attributeState "on", label: 'On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||
attributeState "off", label: 'Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||
attributeState "turningOn", label: 'Turning On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||
attributeState "turningOff", label: 'Turning Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||
}
|
||||
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
||||
attributeState "power", label:'${currentValue} W'
|
||||
|
||||
@@ -43,3 +43,7 @@
|
||||
'''{{ device.displayName }} battery was {{ value }}%'''.ko={{ device.displayName }}남아있는 배터리는 {{ value }}%입니다.
|
||||
'''Updating device to garage sensor'''.ko=기기-차고 센서 업데이트 중
|
||||
'''Updating device to open/close sensor'''.ko=기기-열림/닫힘 센서 업데이트 중
|
||||
'''Inactive'''.ko=비활성
|
||||
'''Active'''.ko=활성
|
||||
'''Open'''.ko=열다
|
||||
'''Closed'''.ko=닫은
|
||||
@@ -83,19 +83,19 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"status", type: "generic", width: 6, height: 4){
|
||||
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
|
||||
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
||||
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
||||
attributeState "open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
||||
attributeState "closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
||||
attributeState "garage-open", label:'Open', icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e"
|
||||
attributeState "garage-closed", label:'Closed', icon:"st.doors.garage.garage-closed", backgroundColor:"#79b821"
|
||||
}
|
||||
}
|
||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||
state("open", label:'Open', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||
state("closed", label:'Closed', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||
}
|
||||
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
||||
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
||||
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
||||
state("active", label:'Active', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
||||
state("inactive", label:'Inactive', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
||||
}
|
||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||
state("temperature", label:'${currentValue}°',
|
||||
|
||||
@@ -87,10 +87,13 @@ def authPage(){
|
||||
}
|
||||
|
||||
def installed() {
|
||||
log.debug "Installed with settings: ${settings}"
|
||||
initialize()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.debug "Updated with settings: ${settings}"
|
||||
unsubscribe()
|
||||
initialize()
|
||||
}
|
||||
|
||||
@@ -103,24 +106,72 @@ def uninstalled() {
|
||||
}
|
||||
|
||||
def initialize() {
|
||||
unsubscribe()
|
||||
atomicState.attached_sensors = [:]
|
||||
if (plantlinksensors){
|
||||
subscribe(plantlinksensors, "moisture_status", moistureHandler)
|
||||
subscribe(plantlinksensors, "battery_status", batteryHandler)
|
||||
plantlinksensors.each{ sensor_device ->
|
||||
subscribe(sensor_device, "moisture_status", moistureHandler)
|
||||
subscribe(sensor_device, "battery_status", batteryHandler)
|
||||
sensor_device.setStatusIcon("Waiting on First Measurement")
|
||||
sensor_device.setInstallSmartApp("connectedToSmartApp")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def updatePlantNameIfNeeded(plant, expected_plant_name){
|
||||
def dock_sensor(device_serial, 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 = [
|
||||
uri : appSettings.https_plantLinkServer,
|
||||
headers : ["Content-Type": "application/json", "Authorization": "Bearer ${atomicState.authToken}"],
|
||||
contentType : "application/json"
|
||||
]
|
||||
if (plant.name != expected_plant_name) {
|
||||
log.debug "renaming plant ${plant.key} - ${expected_plant_name}"
|
||||
log.debug "updating plant for - ${expected_plant_name}"
|
||||
plant_put_params["path"] = "/api/v1/plants/${plant.key}"
|
||||
def plant_put_body_map = [
|
||||
name: expected_plant_name
|
||||
@@ -134,39 +185,32 @@ def updatePlantNameIfNeeded(plant, expected_plant_name){
|
||||
}
|
||||
|
||||
def moistureHandler(event){
|
||||
log.debug "moistureHandler - ${event.value}"
|
||||
|
||||
def expected_plant_name = "${event.displayName} (ST)"
|
||||
def expected_plant_name = "SmartThings - ${event.displayName}"
|
||||
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"
|
||||
|
||||
if (!atomicState.attached_sensors.containsKey(device_serial)){
|
||||
dock_sensor(device_serial, expected_plant_name)
|
||||
}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 = [
|
||||
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: appendedEventWithBatteryInfo
|
||||
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 ->
|
||||
if (parse_api_response(measurement_post_response, 'creating moisture measurement') && measurement_post_response.data.size() >0){
|
||||
if (parse_api_response(measurement_post_response, 'creating moisture measurement') &&
|
||||
measurement_post_response.data.size() >0){
|
||||
def measurement = measurement_post_response.data[0]
|
||||
def plant = measurement.plant
|
||||
|
||||
updatePlantNameIfNeeded(plant, expected_plant_name)
|
||||
|
||||
log.debug plant
|
||||
checkAndUpdatePlantIfNeeded(plant, expected_plant_name)
|
||||
plantlinksensors.each{ sensor_device ->
|
||||
if (sensor_device.id == event.deviceId){
|
||||
sensor_device.setStatusIcon(plant.status)
|
||||
if (plant.last_measurements && plant.last_measurements[0].moisture){
|
||||
sensor_device.setPlantFuelLevel(plant.last_measurements[0].moisture * 100 as int)
|
||||
}
|
||||
|
||||
if (plant.last_measurements && plant.last_measurements[0].battery){
|
||||
sensor_device.setBatteryLevel(plant.last_measurements[0].battery * 100 as int)
|
||||
}
|
||||
@@ -180,7 +224,21 @@ def moistureHandler(event){
|
||||
def batteryHandler(event){
|
||||
def expected_plant_name = "SmartThings - ${event.displayName}"
|
||||
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){
|
||||
@@ -189,12 +247,6 @@ def getDeviceSerialFromEvent(event){
|
||||
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(){
|
||||
atomicState.oauthInitState = UUID.randomUUID().toString()
|
||||
def oauthParams = [
|
||||
@@ -211,13 +263,12 @@ def buildRedirectUrl(){
|
||||
}
|
||||
|
||||
def swapToken(){
|
||||
log.debug "PlantLink Connector - OAuth Token"
|
||||
def code = params.code
|
||||
def oauthState = params.state
|
||||
def stcid = appSettings.client_id
|
||||
def postParams = [
|
||||
method: 'POST',
|
||||
uri: appSettings.https_plantLinkServer,
|
||||
uri: "https://oso-tech.appspot.com",
|
||||
path: "/api/v1/oauth-token",
|
||||
query: [grant_type:'authorization_code', code:params.code, client_id:stcid,
|
||||
client_secret:appSettings.client_secret, redirect_uri: buildRedirectUrl()],
|
||||
@@ -270,11 +321,10 @@ def swapToken(){
|
||||
}
|
||||
|
||||
private refreshAuthToken() {
|
||||
log.debug "PlantLink Connector - Refresh OAuth"
|
||||
def stcid = appSettings.client_id
|
||||
def refreshParams = [
|
||||
method: 'POST',
|
||||
uri: appSettings.https_plantLinkServer,
|
||||
uri: "https://hardware-dot-oso-tech.appspot.com",
|
||||
path: "/api/v1/oauth-token",
|
||||
query: [grant_type:'refresh_token', code:"${atomicState.refreshToken}", client_id:stcid,
|
||||
client_secret:appSettings.client_secret],
|
||||
@@ -283,6 +333,7 @@ private refreshAuthToken() {
|
||||
def jsonMap
|
||||
httpPost(refreshParams) { resp ->
|
||||
if(resp.status == 200){
|
||||
log.debug "OAuth Token refreshed"
|
||||
jsonMap = resp.data
|
||||
if (resp.data) {
|
||||
atomicState.refreshToken = resp?.data?.refresh_token
|
||||
@@ -295,12 +346,12 @@ private refreshAuthToken() {
|
||||
}
|
||||
data.action = ""
|
||||
}else{
|
||||
log.debug "PlantLink Server - ${resp.status} : ${resp.status.code}"
|
||||
log.debug "refresh failed ${resp.status} : ${resp.status.code}"
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
log.debug "PlantLink Connector - OAuth Refresh Failed: " + e
|
||||
log.debug "caught exception refreshing auth token: " + e
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +364,7 @@ def parse_api_response(resp, message) {
|
||||
refreshAuthToken()
|
||||
return false
|
||||
} else {
|
||||
debugEvent("Plantlink Error: ${resp.status} - ${resp.status.code}", true)
|
||||
debugEvent("Authentication error, invalid authentication method, lack of credentials, etc.", true)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ preferences {
|
||||
page name:"pageSetup"
|
||||
page name:"Setup"
|
||||
page name:"Settings"
|
||||
page name: "timeIntervalInput"
|
||||
|
||||
}
|
||||
|
||||
@@ -185,7 +186,8 @@ def Settings() {
|
||||
}
|
||||
}
|
||||
|
||||
page(name: "timeIntervalInput", title: "Only during a certain time", refreshAfterSelection:true) {
|
||||
def timeIntervalInput() {
|
||||
dynamicPage(name: "timeIntervalInput") {
|
||||
section {
|
||||
input "startTimeType", "enum", title: "Starting at", options: [["time": "A specific time"], ["sunrise": "Sunrise"], ["sunset": "Sunset"]], defaultValue: "time", submitOnChange: true
|
||||
if (startTimeType in ["sunrise","sunset"]) {
|
||||
@@ -204,9 +206,10 @@ page(name: "timeIntervalInput", title: "Only during a certain time", refreshAfte
|
||||
input "ending", "time", title: "End time", required: false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def installed() {
|
||||
initialize()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user