/**
* Hubigraph Radar Tile Child App
*
* Copyright 2020, but let's behonest, you'll copy it
*
* 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.
*
* Utilizes the Windy.com embedded map ability
*/
// Hubigraph Gauge Change Log
// V 0.1 Intial release
// V 1.0 Released (not Beta) Cleanup and Preview Enabled
// V 1.5 Ordering, Color and Common API Update
// V 1.8 Smoother sliders, bug fixes
import groovy.json.JsonOutput
import java.text.DecimalFormat;
def ignoredEvents() { return [ 'lastReceive' , 'reachable' ,
'buttonReleased' , 'buttonPressed', 'lastCheckinDate', 'lastCheckin', 'buttonHeld' ] }
def version() { return "v0.22" }
definition(
name: "Hubigraph Radar Tile",
namespace: "tchoward",
author: "Thomas Howard",
description: "Hubigraph Radar Tile",
category: "",
parent: "tchoward:Hubigraphs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
)
preferences {
section ("test"){
page(name: "mainPage", install: true, uninstall: true)
page(name: "tileSetupPage", nextPage: "mainPage")
page(name: "enableAPIPage")
page(name: "disableAPIPage")
}
mappings {
path("/graph/") {
action: [
GET: "getGraph"
]
}
}
}
def call(Closure code) {
code.setResolveStrategy(Closure.DELEGATE_ONLY);
code.setDelegate(this);
code.call();
}
def tileSetupPage() {
def supported_attrs;
zoomEnum = [[3:"3"], [4: "4"], [5: "5"], [6: "6"], [7: "7"], [8: "8"], [9: "9"], [10: "10"]];
refreshEnum = [[60000:"1 minute"], [300000: "5 minutes"], [600000: "10 minutes"], [1200000: "20 minutes"], [1800000: "30 minutes"], [3600000: "1 hour"]];
weatherMapEnum = [["radar" : "Current Radar"],
["temp" : "Temperature"],
["wind" : "Wind"],
["rain" : "Rain and Thunder"],
["rainAccu" : "Rain Accumulation"],
["snowAccu" : "Snow Accumulation"],
["snowcover": "Snow Ground Cover"]];
forecastModelEnum =[["ecmwf": "European Centre for Medium-Range Weather Forecasts"],
["gfs": "Global Forecast System"]];
hoursModelEnum = [["now" : "Current"],
["12" : "12 Hours"],
["24" : "24 Hours"]];
measureEnum = [["in": "inches"],
["mm": "millimeters"]];
windEnum = [["knot" : "Knots (k)"],
["meters_per_second" : "Meters / Second (m/s)"],
["kilometers_per_hour" : "Kilometers / Hour (km/h)"],
["miles_per_hour" : "Miles per Hour (mph)"]];
tempEnum = [["fahrenheit": "Fahrenheit (°F)"],
["celsius" : "Celsius (°C)"]];
dynamicPage(name: "tileSetupPage") {
def location = getLocation();
parent.hubiForm_section(this,"Tile Setup", 1){
container = [];
container << parent.hubiForm_text_input (this, "Latitude (Default = Hub location)", "latitude", location.latitude, false);
container << parent.hubiForm_text_input (this, "Longitude (Default = Hub location)", "longitude", location.longitude, false);
parent.hubiForm_container(this, container, 1);
if (!overlay) overlay = "radar";
input( type: "enum", name: "zoom", title: "Zoom Amount", required: false, multiple: false, options: zoomEnum, defaultValue: 3, submitOnChange: false)
input( type: "enum", name: "refresh", title: "Refresh Time", required: false, multiple: false, options: refreshEnum, defaultValue: 600000, submitOnChange: false)
input( type: "enum", name: "overlay", title: "Map Type", required: false, multiple: false, options: weatherMapEnum, defaultValue: "radar", submitOnChange: true)
if (overlay != "radar") {
container = [];
container << parent.hubiForm_text(this, """You have chosen a forecast map. Please note:
1. Forecast maps are update on the hour
2. "Current" is the current condition (within the last hour)
3. Refreshing these maps "more often" won't change anything""");
parent.hubiForm_container(this, container, 1);
if (product == "radar") app.updateSetting("product", [type: "enum", value: "gfs"]);
input( type: "enum", name: "product", title: "Forecast Model", required: false, multiple: false, options: forecastModelEnum, defaultValue: "gfs", submitOnChange: false);
input( type: "enum", name: "calendar", title: "Display Time", required: false, multiple: false, options: hoursModelEnum, defaultValue: "now", submitOnChange: false);
} else {
app.updateSetting ("product", [type: "enum", value: "radar"]);
app.updateSetting ("calendar", [type: "enum", value: "now"]);
}
input( type: "enum", name: "wind_units", title: "Wind Speed Units", required: false, multiple: false, options: windEnum, defaultValue: "miles_per_hour", submitOnChange: false);
input( type: "enum", name: "temp_units", title: "Temperature Units", required: false, multiple: false, options: tempEnum, defaultValue: "farenheit", submitOnChange: false);
container = [];
container << parent.hubiForm_switch(this, title: "Show Marker on Graph?",
name: "marker",
default: false,
submit_on_change: false);
container << parent.hubiForm_color(this, "Background",
"background",
"#000000",
false);
container << parent.hubiForm_slider (this, title: "Background Opacity",
name: "background_opacity",
default: 90,
min: 0,
max: 100,
units: "%",
submit_on_change: false);
parent.hubiForm_container(this, container, 1);
}
}
}
def disableAPIPage() {
dynamicPage(name: "disableAPIPage") {
section() {
if (state.endpoint) {
try {
revokeAccessToken();
}
catch (e) {
}
state.endpoint = null
}
paragraph "It has been done. Your token has been REVOKED. Tap Done to continue."
}
}
}
def enableAPIPage() {
dynamicPage(name: "enableAPIPage", title: "") {
section() {
if(!state.endpoint) initializeAppEndpoint();
if (!state.endpoint){
paragraph "Endpoint creation failed"
} else {
paragraph "It has been done. Your token has been CREATED. Tap Done to continue."
}
}
}
}
def mainPage() {
dynamicPage(name: "mainPage") {
def container = [];
if (!state.endpoint) {
parent.hubiForm_section(this, "Please set up OAuth API", 1, "report"){
href name: "enableAPIPageLink", title: "Enable API", description: "", page: "enableAPIPage"
}
} else {
parent.hubiForm_section(this, "Graph Options", 1, "tune"){
container = [];
container << parent.hubiForm_page_button(this, "Setup Tile", "tileSetupPage", "100%", "vibration");
parent.hubiForm_container(this, container, 1);
}
parent.hubiForm_section(this, "Local Graph URL", 1, "link"){
container = [];
container << parent.hubiForm_text(this, "${state.localEndpointURL}graph/?access_token=${state.endpointSecret}");
parent.hubiForm_container(this, container, 1);
}
// if (gauge_title){
parent.hubiForm_section(this, "Preview", 10, "show_chart"){
container = [];
container << parent.hubiForm_graph_preview(this)
parent.hubiForm_container(this, container, 1);
} //graph_timespan
parent.hubiForm_section(this, "Hubigraph Tile Installation", 2, "apps"){
container = [];
container << parent.hubiForm_switch(this, title: "Install Hubigraph Tile Device?", name: "install_device", default: false, submit_on_change: true);
if (install_device==true){
container << parent.hubiForm_text_input(this, "Name for HubiGraph Tile Device", "device_name", "Hubigraph Radar Tile", "false");
}
parent.hubiForm_container(this, container, 1);
}
// }
if (state.endpoint){
parent.hubiForm_section(this, "Hubigraph Application", 1, "settings"){
container = [];
container << parent.hubiForm_sub_section(this, "Application Name");
container << parent.hubiForm_text_input(this, "Rename the Application?", "app_name", "Hubigraph Radar", "false");
container << parent.hubiForm_sub_section(this, "Debugging");
container << parent.hubiForm_switch(this, title: "Enable Debug Logging?", name: "debug", default: false);
container << parent.hubiForm_sub_section(this, "Disable Oauth Authorization");
container << parent.hubiForm_page_button(this, "Disable API", "disableAPIPage", "100%", "cancel");
parent.hubiForm_container(this, container, 1);
}
}
} //else
} //dynamicPage
}
def installed() {
log.debug "Installed with settings: ${settings}"
updated();
}
def uninstalled() {
if (state.endpoint) {
try {
log.debug "Revoking API access token"
revokeAccessToken()
}
catch (e) {
log.warn "Unable to revoke API access token: $e"
}
}
removeChildDevices(getChildDevices());
}
private removeChildDevices(delete) {
delete.each {deleteChildDevice(it.deviceNetworkId)}
}
def updated() {
app.updateLabel(app_name);
state.dataName = attribute;
if (install_device == true){
parent.hubiTool_create_tile(this);
}
}
def buildData() {
return extractNumber(sensor_.currentState(attribute_).getStringValue());
}
def getRGBA(hex, opacity){
def c = hex-"#";
c = c.toUpperCase();
i = Integer.parseInt(c, 16);
r = (i & 0xFF0000) >> 16;
g = (i & 0xFF00) >> 8;
b = (i & 0xFF);
o = opacity/100.0;
s = sprintf("rgba( %d, %d, %d, %.2f)", r, g, b, o);
return s;
}
def getHTML(){
def fullSizeStyle = "margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden";
def wind = "kt";
switch (wind_units){
case "knot" : wind = "kt"; break;
case "meters_per_second" : wind = "m%2Fs"; break;
case "kilometers_per_hour" : wind = "km%2Fh"; break;
case "miles_per_hour" : wind = "mph"; break;
}
def temp = "%C2%B0F";
switch (temp_units){
case "farenheit": temp = "%C2%B0F";
case "celsius" : temp = "%C2%B0C"
}
def html = """