mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-05-22 06:08:51 +01:00
Modifying 'LaMetric Time device handler and smart apps'
This commit is contained in:
@@ -15,22 +15,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
|
||||
definition(
|
||||
name: "LaMetric (Connect)",
|
||||
namespace: "com.lametric",
|
||||
author: "Mykola Kirichuk",
|
||||
description: "Lametric connect",
|
||||
category: "Fun & Social",
|
||||
description: "Control your LaMetric Time smart display",
|
||||
category: "Family",
|
||||
iconUrl: "https://developer.lametric.com/assets/smart_things/smart_things_60.png",
|
||||
iconX2Url: "https://developer.lametric.com/assets/smart_things/smart_things_120.png",
|
||||
iconX3Url: "https://developer.lametric.com/assets/smart_things/smart_things_120.png",
|
||||
singleInstance: true)
|
||||
{
|
||||
{
|
||||
appSetting "clientId"
|
||||
appSetting "clientSecret"
|
||||
}
|
||||
}
|
||||
|
||||
preferences {
|
||||
page(name: "auth", title: "LaMetric", nextPage:"", content:"authPage", uninstall: true, install:true)
|
||||
@@ -42,6 +40,7 @@ mappings {
|
||||
path("/oauth/callback") {action: [GET: "callback"]}
|
||||
}
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
|
||||
def getEventNameListOfUserDeviceParsed(){ "EventListOfUserRemoteDevicesParsed" }
|
||||
def getEventNameTokenRefreshed(){ "EventAuthTokenRefreshed" }
|
||||
@@ -72,50 +71,50 @@ def initialize() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the new device to instantiate in the user's smartapps
|
||||
* This must be an app owned by the namespace (see #getNameSpace).
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
* Get the name of the new device to instantiate in the user's smartapps
|
||||
* This must be an app owned by the namespace (see #getNameSpace).
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
|
||||
def getDeviceName() {
|
||||
return "LaMetric"
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the namespace this app and siblings use
|
||||
*
|
||||
* @return namespace
|
||||
*/
|
||||
* Returns the namespace this app and siblings use
|
||||
*
|
||||
* @return namespace
|
||||
*/
|
||||
def getNameSpace() {
|
||||
return "com.lametric"
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all discovered devices or an empty array if none
|
||||
*
|
||||
* @return array of devices
|
||||
*/
|
||||
* Returns all discovered devices or an empty array if none
|
||||
*
|
||||
* @return array of devices
|
||||
*/
|
||||
def getDevices() {
|
||||
state.remoteDevices = state.remoteDevices ?: [:]
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of devices which have been verified
|
||||
*
|
||||
* @return array of verified devices
|
||||
*/
|
||||
* Returns an array of devices which have been verified
|
||||
*
|
||||
* @return array of verified devices
|
||||
*/
|
||||
def getVerifiedDevices() {
|
||||
getDevices().findAll{ it?.value?.verified == true }
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a Map object which can be used with a preference page
|
||||
* to represent a list of devices detected and verified.
|
||||
*
|
||||
* @return Map with zero or more devices
|
||||
*/
|
||||
* Generates a Map object which can be used with a preference page
|
||||
* to represent a list of devices detected and verified.
|
||||
*
|
||||
* @return Map with zero or more devices
|
||||
*/
|
||||
Map getSelectableDevice() {
|
||||
def devices = getVerifiedDevices()
|
||||
def map = [:]
|
||||
@@ -128,9 +127,9 @@ Map getSelectableDevice() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the refresh loop, making sure to keep us up-to-date with changes
|
||||
*
|
||||
*/
|
||||
* Starts the refresh loop, making sure to keep us up-to-date with changes
|
||||
*
|
||||
*/
|
||||
private refreshDevices(){
|
||||
log.debug "refresh device list"
|
||||
listOfUserRemoteDevices()
|
||||
@@ -139,21 +138,21 @@ private refreshDevices(){
|
||||
}
|
||||
|
||||
/**
|
||||
* The deviceDiscovery page used by preferences. Will automatically
|
||||
* make calls to the underlying discovery mechanisms as well as update
|
||||
* whenever new devices are discovered AND verified.
|
||||
*
|
||||
* @return a dynamicPage() object
|
||||
*/
|
||||
* The deviceDiscovery page used by preferences. Will automatically
|
||||
* make calls to the underlying discovery mechanisms as well as update
|
||||
* whenever new devices are discovered AND verified.
|
||||
*
|
||||
* @return a dynamicPage() object
|
||||
*/
|
||||
/******************************************************************************************************************
|
||||
DEVICE DISCOVERY AND VALIDATION
|
||||
DEVICE DISCOVERY AND VALIDATION
|
||||
******************************************************************************************************************/
|
||||
def deviceDiscovery()
|
||||
{
|
||||
// if(canInstallLabs())
|
||||
// if(canInstallLabs())
|
||||
if (1)
|
||||
{
|
||||
// userDeviceList();
|
||||
// userDeviceList();
|
||||
log.debug("deviceDiscovery")
|
||||
def refreshInterval = 3 // Number of seconds between refresh
|
||||
int deviceRefreshCount = !state.deviceRefreshCount ? 0 : state.deviceRefreshCount as int
|
||||
@@ -166,9 +165,9 @@ def deviceDiscovery()
|
||||
subscribeNetworkEvents()
|
||||
|
||||
//device discovery request every 15s
|
||||
// if((deviceRefreshCount % 15) == 0) {
|
||||
// discoverLaMetrics()
|
||||
// }
|
||||
// if((deviceRefreshCount % 15) == 0) {
|
||||
// discoverLaMetrics()
|
||||
// }
|
||||
|
||||
// Verify request every 3 seconds except on discoveries
|
||||
if(((deviceRefreshCount % 5) == 0)) {
|
||||
@@ -200,10 +199,10 @@ To update your Hub, access Location Settings in the Main Menu (tap the gear next
|
||||
/**
|
||||
|
||||
/**
|
||||
* Starts a subscription for network events
|
||||
*
|
||||
* @param force If true, will unsubscribe and subscribe if necessary (Optional, default false)
|
||||
*/
|
||||
* Starts a subscription for network events
|
||||
*
|
||||
* @param force If true, will unsubscribe and subscribe if necessary (Optional, default false)
|
||||
*/
|
||||
private subscribeNetworkEvents(force=false) {
|
||||
if (force) {
|
||||
unsubscribe()
|
||||
@@ -212,7 +211,7 @@ private subscribeNetworkEvents(force=false) {
|
||||
if(!state.subscribe) {
|
||||
log.debug("subscribe on network events")
|
||||
subscribe(location, null, locationHandler, [filterEvents:false])
|
||||
// subscribe(app, appHandler)
|
||||
// subscribe(app, appHandler)
|
||||
state.subscribe = true
|
||||
}
|
||||
}
|
||||
@@ -290,7 +289,7 @@ def locationHandler(evt)
|
||||
if (parsedJsonBody)
|
||||
{
|
||||
log.trace (parsedJsonBody)
|
||||
log.debug("responce for device ${parsedJsonBody?.server_id}")
|
||||
log.debug("responce for device ${parsedJsonBody?.id}")
|
||||
//put or post response
|
||||
if (parsedJsonBody.success)
|
||||
{
|
||||
@@ -298,8 +297,8 @@ def locationHandler(evt)
|
||||
} else {
|
||||
//poll response
|
||||
log.debug "poll responce"
|
||||
log.debug ("poll responce ${parsedJsonBody?.info}")
|
||||
def deviceId = parsedJsonBody?.info?.server_id;
|
||||
log.debug ("poll responce ${parsedJsonBody}")
|
||||
def deviceId = parsedJsonBody?.id;
|
||||
if (deviceId)
|
||||
{
|
||||
def devices = getDevices();
|
||||
@@ -328,10 +327,10 @@ def locationHandler(evt)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the child devices based on the user's selection
|
||||
*
|
||||
* Uses selecteddevice defined in the deviceDiscovery() page
|
||||
*/
|
||||
* Adds the child devices based on the user's selection
|
||||
*
|
||||
* Uses selecteddevice defined in the deviceDiscovery() page
|
||||
*/
|
||||
def addDevice() {
|
||||
def devices = getVerifiedDevices()
|
||||
def devlist
|
||||
@@ -430,27 +429,6 @@ def authPage() {
|
||||
subscribeNetworkEvents()
|
||||
listOfUserRemoteDevices()
|
||||
return deviceDiscovery();
|
||||
/*
|
||||
return deviceDiscovery();
|
||||
|
||||
def stats = getEcobeeThermostats()
|
||||
log.debug "thermostat list: $stats"
|
||||
log.debug "sensor list: ${sensorsDiscovered()}"
|
||||
return dynamicPage(name: "auth", title: "Select Your Thermostats", uninstall: true) {
|
||||
section(""){
|
||||
paragraph "Tap below to see the list of ecobee thermostats available in your ecobee account and select the ones you want to connect to SmartThings."
|
||||
input(name: "thermostats", title:"", type: "enum", required:true, multiple:true, description: "Tap to choose", metadata:[values:stats])
|
||||
}
|
||||
|
||||
def options = sensorsDiscovered() ?: []
|
||||
def numFound = options.size() ?: 0
|
||||
if (numFound > 0) {
|
||||
section(""){
|
||||
paragraph "Tap below to see the list of ecobee sensors available in your ecobee account and select the ones you want to connect to SmartThings."
|
||||
input(name: "ecobeesensors", title:"Select Ecobee Sensors (${numFound} found)", type: "enum", required:false, description: "Tap to choose", multiple:true, options:options)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,17 +555,17 @@ def oauthInitUrl() {
|
||||
|
||||
def success() {
|
||||
def message = """
|
||||
<p>Your LaMetric Account is now connected to SmartThings!</p>
|
||||
<p>Click 'Done' to finish setup.</p>
|
||||
"""
|
||||
<p>Your LaMetric Account is now connected to SmartThings!</p>
|
||||
<p>Click 'Done' to finish setup.</p>
|
||||
"""
|
||||
connectionStatus(message)
|
||||
}
|
||||
|
||||
def fail() {
|
||||
def message = """
|
||||
<p>The connection could not be established!</p>
|
||||
<p>Click 'Done' to return to the menu.</p>
|
||||
"""
|
||||
<p>The connection could not be established!</p>
|
||||
<p>Click 'Done' to return to the menu.</p>
|
||||
"""
|
||||
connectionStatus(message)
|
||||
}
|
||||
|
||||
@@ -595,111 +573,111 @@ def connectionStatus(message, redirectUrl = null) {
|
||||
def redirectHtml = ""
|
||||
if (redirectUrl) {
|
||||
redirectHtml = """
|
||||
<meta http-equiv="refresh" content="3; url=${redirectUrl}" />
|
||||
"""
|
||||
<meta http-equiv="refresh" content="3; url=${redirectUrl}" />
|
||||
"""
|
||||
}
|
||||
|
||||
def html = """
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"><head>
|
||||
<meta charset="UTF-8">
|
||||
<meta content="width=device-width" id="viewport" name="viewport">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'latoRegular';
|
||||
src: url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.eot");
|
||||
src: url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.eot?#iefix") format("embedded-opentype"),
|
||||
url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.woff") format("woff"),
|
||||
url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.ttf") format("truetype"),
|
||||
url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.svg#latoRegular") format("svg");
|
||||
font-style: normal;
|
||||
font-weight: normal; }
|
||||
.clearfix:after, .mobile .connect:after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table; }
|
||||
<meta charset="UTF-8">
|
||||
<meta content="width=device-width" id="viewport" name="viewport">
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'latoRegular';
|
||||
src: url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.eot");
|
||||
src: url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.eot?#iefix") format("embedded-opentype"),
|
||||
url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.woff") format("woff"),
|
||||
url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.ttf") format("truetype"),
|
||||
url("https://developer.lametric.com/assets/fonts/lato-regular-webfont.svg#latoRegular") format("svg");
|
||||
font-style: normal;
|
||||
font-weight: normal; }
|
||||
.clearfix:after, .mobile .connect:after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table; }
|
||||
|
||||
.transition {
|
||||
transition: all .3s ease 0s; }
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #f0f0f0;
|
||||
color: #5c5c5c;
|
||||
min-width: 1149px;
|
||||
font-family: 'latoRegular', 'Lato';
|
||||
}
|
||||
.fixed-page #page {
|
||||
min-height: 100%;
|
||||
background: url(https://developer.lametric.com/assets/smart_things/page-bg.png) 50% 0 repeat-y;
|
||||
}
|
||||
.mobile {
|
||||
min-width: 100%;
|
||||
color: #757575; }
|
||||
.mobile .wrap {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
max-width: 640px;
|
||||
min-width: inherit; }
|
||||
.mobile .connect {
|
||||
width: 100%;
|
||||
padding-top: 230px;
|
||||
margin-bottom: 50px;
|
||||
text-align: center; }
|
||||
.mobile .connect img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
margin-left: 2%;
|
||||
border-radius: 15px; }
|
||||
.mobile .connect img:first-child {
|
||||
margin-left: 0; }
|
||||
.mobile .info {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 50px; }
|
||||
.mobile .info p {
|
||||
max-width: 80%;
|
||||
margin: 0 auto;
|
||||
margin-top: 50px;
|
||||
font-size: 28px;
|
||||
line-height: 50px;
|
||||
text-align: center; }
|
||||
.transition {
|
||||
transition: all .3s ease 0s; }
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
body{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #f0f0f0;
|
||||
color: #5c5c5c;
|
||||
min-width: 1149px;
|
||||
font-family: 'latoRegular', 'Lato';
|
||||
}
|
||||
.fixed-page #page {
|
||||
min-height: 100%;
|
||||
background: url(https://developer.lametric.com/assets/smart_things/page-bg.png) 50% 0 repeat-y;
|
||||
}
|
||||
.mobile {
|
||||
min-width: 100%;
|
||||
color: #757575; }
|
||||
.mobile .wrap {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
max-width: 640px;
|
||||
min-width: inherit; }
|
||||
.mobile .connect {
|
||||
width: 100%;
|
||||
padding-top: 230px;
|
||||
margin-bottom: 50px;
|
||||
text-align: center; }
|
||||
.mobile .connect img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
margin-left: 2%;
|
||||
border-radius: 15px; }
|
||||
.mobile .connect img:first-child {
|
||||
margin-left: 0; }
|
||||
.mobile .info {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 50px; }
|
||||
.mobile .info p {
|
||||
max-width: 80%;
|
||||
margin: 0 auto;
|
||||
margin-top: 50px;
|
||||
font-size: 28px;
|
||||
line-height: 50px;
|
||||
text-align: center; }
|
||||
|
||||
@media screen and (max-width: 639px) {
|
||||
.mobile .connect{
|
||||
padding-top: 100px; }
|
||||
.mobile .wrap {
|
||||
margin: 0 20px; }
|
||||
.mobile .connect img {
|
||||
width: 16%; }
|
||||
.mobile .connect img:first-child, .mobile .connect img:last-child {
|
||||
width: 40%; }
|
||||
.mobile .info p{
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
margin-top: 20px; }
|
||||
}
|
||||
</style>
|
||||
@media screen and (max-width: 639px) {
|
||||
.mobile .connect{
|
||||
padding-top: 100px; }
|
||||
.mobile .wrap {
|
||||
margin: 0 20px; }
|
||||
.mobile .connect img {
|
||||
width: 16%; }
|
||||
.mobile .connect img:first-child, .mobile .connect img:last-child {
|
||||
width: 40%; }
|
||||
.mobile .info p{
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
margin-top: 20px; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="fixed-page mobile">
|
||||
|
||||
<div id="page">
|
||||
<div class="wrap">
|
||||
<div class="wrap">
|
||||
|
||||
<div class="connect">
|
||||
<img src="https://developer.lametric.com/assets/smart_things/product.png" width="190" height="190"><img src="https://developer.lametric.com/assets/smart_things/connected.png" width="87" height="19"><img src="https://developer.lametric.com/assets/smart_things/product-1.png" width="192" height="192">
|
||||
</div>
|
||||
<div class="connect">
|
||||
<img src="https://developer.lametric.com/assets/smart_things/product.png" width="190" height="190"><img src="https://developer.lametric.com/assets/smart_things/connected.png" width="87" height="19"><img src="https://developer.lametric.com/assets/smart_things/product-1.png" width="192" height="192">
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
${message}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
${message}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body></html>
|
||||
"""
|
||||
@@ -713,8 +691,8 @@ def connectionStatus(message, redirectUrl = null) {
|
||||
//******************************************************************************************************************
|
||||
|
||||
def getLocalApiDeviceInfoPath() { "/api/v2/info" }
|
||||
def getLocalApiSendNotificationPath() { "/api/v2/notifications" }
|
||||
def getLocalApiIndexPath() { "/api/v2" }
|
||||
def getLocalApiSendNotificationPath() { "/api/v2/device/notifications" }
|
||||
def getLocalApiIndexPath() { "/api/v2/device" }
|
||||
def getLocalApiUser() { "dev" }
|
||||
|
||||
|
||||
@@ -765,14 +743,15 @@ def getAllInfoFromDevice(localIp, apiKey)
|
||||
log.debug "send something"
|
||||
if (localIp && apiKey)
|
||||
{
|
||||
sendHubCommand(new physicalgraph.device.HubAction([
|
||||
def hubCommand = new physicalgraph.device.HubAction([
|
||||
method: "GET",
|
||||
path: localApiIndexPath,
|
||||
query:["fields": ["info","wifi", "volume", "bluetooth"]],
|
||||
path: localApiIndexPath+"?fields=info,wifi,volume,bluetooth,id,name,mode,model,serial_number,os_version",
|
||||
headers: [
|
||||
HOST: "${localIp}:8080",
|
||||
Authorization: "Basic ${"${localApiUser}:${apiKey}".bytes.encodeBase64()}"
|
||||
]]))
|
||||
]])
|
||||
log.debug "sending request ${hubCommand}"
|
||||
sendHubCommand(hubCommand)
|
||||
}
|
||||
}
|
||||
//******************************************************************************************************************
|
||||
@@ -787,9 +766,9 @@ def resolveDNI2Device(dni)
|
||||
def requestRefreshDeviceInfo (dni)
|
||||
{
|
||||
log.debug "device ${dni} request refresh";
|
||||
// def devices = getDevices();
|
||||
// def concreteDevice = devices[dni];
|
||||
// requestDeviceInfo(conreteDevice);
|
||||
// def devices = getDevices();
|
||||
// def concreteDevice = devices[dni];
|
||||
// requestDeviceInfo(conreteDevice);
|
||||
}
|
||||
|
||||
private poll(dni) {
|
||||
@@ -837,13 +816,7 @@ void listOfUserRemoteDevices()
|
||||
log.debug ("empty device info")
|
||||
}
|
||||
}
|
||||
// state.remoteDevices = remoteDevices;
|
||||
verifyDevices();
|
||||
// return
|
||||
// def serializedData = new JsonOutput().toJson(notification);
|
||||
// app.sendEvent(name: "EventListOfUserRemoteDevicesParsed", value: serializedData)
|
||||
// app.sendEvent(name: "parsed", value: true)
|
||||
// log.debug "Sending 'save new list' event ${result}"
|
||||
} else {
|
||||
log.debug "http status: ${resp.status}"
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ definition(
|
||||
name: "LaMetric Notifier",
|
||||
namespace: "com.lametric",
|
||||
author: "Mykola Kirichuk",
|
||||
description: "Notify about changes with sound and message on your LaMetric",
|
||||
category: "Fun & Social",
|
||||
description: "Allows you to send notifications to your LaMetric Time when something happens in your home to notify the whole family.",
|
||||
category: "Family",
|
||||
iconUrl: "https://developer.lametric.com/assets/smart_things/weather_60.png",
|
||||
iconX2Url: "https://developer.lametric.com/assets/smart_things/weather_120.png",
|
||||
iconX3Url: "https://developer.lametric.com/assets/smart_things/weather_120.png")
|
||||
@@ -388,21 +388,8 @@ def eventHandler(evt) {
|
||||
|
||||
if (allOk) {
|
||||
log.trace "allOk"
|
||||
// def lastTime = state[frequencyKey(evt)]
|
||||
// if (oncePerDayOk(lastTime)) {
|
||||
/*
|
||||
if (frequency) {
|
||||
if (lastTime == null || now() - lastTime >= frequency * 60000) {
|
||||
takeAction(evt)
|
||||
}
|
||||
else {
|
||||
log.debug "Not taking action because $frequency minutes have not elapsed since last action"
|
||||
}
|
||||
/* }
|
||||
else {*/
|
||||
takeAction(evt)
|
||||
// }
|
||||
}
|
||||
else {
|
||||
log.debug "Not taking action because it was already taken today"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user