Modifying 'LaMetric Time device handler and smart apps'

This commit is contained in:
Nazar Bilous
2016-06-24 11:18:02 -05:00
parent ab61db3699
commit 6e32676fe5
2 changed files with 392 additions and 432 deletions
@@ -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"
}