/**
* Hubigraph RangeBar 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.
*
*/
// Hubigraph RangeBar Changelog
// V 0.1 Intial release
// V 0.2 Ordering, Color and Common API Update
// V 1.8 Smoother sliders, bug fixes
import groovy.json.JsonOutput
def ignoredEvents() { return [ 'lastReceive' , 'reachable' ,
'buttonReleased' , 'buttonPressed', 'lastCheckinDate', 'lastCheckin', 'buttonHeld' ] }
def version() { return "v0.22" }
definition(
name: "Hubigraph Range Bar",
namespace: "tchoward",
author: "Thomas Howard",
description: "Hubigraph Range Bar",
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: "deviceSelectionPage", nextPage: "attributeConfigurationPage")
page(name: "attributeConfigurationPage", nextPage: "mainPage")
page(name: "graphSetupPage", nextPage: "mainPage")
page(name: "enableAPIPage")
page(name: "disableAPIPage")
}
mappings {
path("/graph/") {
action: [
GET: "getGraph"
]
}
}
path("/getData/") {
action: [
GET: "getData"
]
}
path("/getOptions/") {
action: [
GET: "getOptions"
]
}
path("/getSubscriptions/") {
action: [
GET: "getSubscriptions"
]
}
}
def call(Closure code) {
code.setResolveStrategy(Closure.DELEGATE_ONLY);
code.setDelegate(this);
code.call();
}
def getAttributeType(attrib, title){
switch (attrib){
case "motion": return ["motion", "Motion (active/inactive)"];
case "switch": return ["switch", "Switch (on/off)"];
case "contact": return ["contact", "Contact (open/close)"];
case "acceleration": return ["acceleration", "Acceleration (active/inactive)"]
case "audioVolume":
case "number": return [title, "Number (Choose threshold)"];
}
}
def deviceSelectionPage() {
dynamicPage(name: "deviceSelectionPage") {
parent.hubiForm_section(this, "Device Selection", 1) {
input (type: "capability.*", name: "sensors", title: "Choose Sensors", multiple: true, submitOnChange: true)
if (sensors) {
def all = (1..sensors.size()).collect{ "" + it };
parent.hubiTools_validate_order(this, all);
sensors.eachWithIndex {sensor, idx ->
id = sensor.id;
sensor_attributes = sensor.getSupportedAttributes().collect { it.getName() };
container = [];
container << parent.hubiForm_sub_section(this, "${sensor.displayName}");
parent.hubiForm_container(this, container, 1);
input( type: "enum", name: "attributes_${id}", title: "Attributes to graph", required: true, multiple: true, options: sensor_attributes, defaultValue: "1", submitOnChange: false )
}
}
}
}
}
def attributeConfigurationPage() {
state.count_ = 0;
dynamicPage(name: "attributeConfigurationPage") {
parent.hubiForm_section(this, "Directions", 1, "directions"){
container = [];
container << parent.hubiForm_text(this, "Choose Numeric Attributes Only");
parent.hubiForm_container(this, container, 1);
}
parent.hubiForm_section(this, "Graph Order", 1, "directions"){
parent.hubiForm_list_reorder(this, "graph_order", "background", "#3e4475");
}
cnt = 1;
sensors.each { sensor ->
def attributes = settings["attributes_${sensor.id}"];
attributes.each { attribute ->
state.count_++;
parent.hubiForm_section(this, "${sensor.displayName} - ${attribute}", 1, "direction"){
container = [];
container << parent.hubiForm_text_input(this, "Override Device Name
Use %deviceName% for DEVICE and %attributeName% for ATTRIBUTE",
"graph_name_override_${sensor.id}_${attribute}",
"%deviceName%: %attributeName%", false);
container << parent.hubiForm_color (this, "Bar Background", "attribute_${sensor.id}_${attribute}_background","#5b626e", false, true);
container << parent.hubiForm_color (this, "Min/Max", "attribute_${sensor.id}_${attribute}_minmax", "#607c91", false);
container << parent.hubiForm_color (this, "Current Value", "attribute_${sensor.id}_${attribute}_current", "#8eb6d4", false);
container << parent.hubiForm_color (this, "Current Value Border", "attribute_${sensor.id}_${attribute}_current_border", "#FFFFFF", false);
container << parent.hubiForm_switch (this, title: "Show Current Value on Bar?", name: "attribute_${sensor.id}_${attribute}_show_value", default: false, submit_on_change: true);
if (settings["attribute_${sensor.id}_${attribute}_show_value"]==true){
container << parent.hubiForm_text_input(this, "Units", "attribute_${sensor.id}_${attribute}_annotation_units", "", false)
}
parent.hubiForm_container(this, container, 1);
}
cnt += 1;
}
}
}
}
def graphSetupPage(){
def rateEnum = [["-1":"Never"], ["0":"Real Time"], ["10":"10 Milliseconds"], ["1000":"1 Second"], ["5000":"5 Seconds"], ["60000":"1 Minute"],
["300000":"5 Minutes"], ["600000":"10 Minutes"], ["1800000":"Half Hour"], ["3600000":"1 Hour"]];
def timespanEnum = [[0:"Live"], [1:"Hourly"], [2:"Daily"], [3:"Every Three Days"], [4:"Weekly"]];
dynamicPage(name: "graphSetupPage") {
parent.hubiForm_section(this, "General Options", 1){
container = [];
input( type: "enum", name: "graph_type", title: "Select graph type", multiple: false, required: false, options: [["1": "Bar Chart"],["2": "Column Chart"]], defaultValue: "1");
input( type: "enum", name: "graph_update_rate", title: "Select graph update rate", multiple: false, required: false, options: rateEnum, defaultValue: "0")
input( type: "enum", name: "graph_timespan", title: "Select Timespan to Graph (i.e How Often to Reset Range)", multiple: false, required: false, options: timespanEnum, defaultValue: "2", submitOnChange: true)
container << parent.hubiForm_color (this, "Graph Background", "graph_background", "#FFFFFF", false)
container << parent.hubiForm_slider (this, title: "Graph Bar Width (1%-100%)", name: "graph_bar_percent", default_value: 90, min: 1, max: 100, units: "%");
container << parent.hubiForm_text_input(this, "Graph Max", "graph_max", "100", false);
container << parent.hubiForm_text_input(this, "Graph Min", "graph_min", "0", false);
parent.hubiForm_container(this, container, 1);
}
parent.hubiForm_section(this, "Axes", 1){
container = [];
container << parent.hubiForm_color (this, "Axis", "haxis", "#000000", false);
container << parent.hubiForm_font_size (this, title: "Axis", name: "haxis", default: 9, min: 2, max: 20);
container << parent.hubiForm_slider (this, title: "Number of Pixels for Axis", name: "graph_h_buffer", default_value: 40, min: 10, max: 500, units: " pixels");
parent.hubiForm_container(this, container, 1);
}
parent.hubiForm_section(this, "Device Names", 1){
container = [];
container << parent.hubiForm_font_size (this, title: "Device Name", name: "graph_axis", default: 9, min: 2, max: 20);
container << parent.hubiForm_color (this, "Device Name","graph_axis", "#000000", false);
container << parent.hubiForm_slider (this, title: "Number of Pixels for Device Name Area", name: "graph_v_buffer", default_value: 100, min: 10, max: 500, units: " pixels");
parent.hubiForm_container(this, container, 1);
}
parent.hubiForm_section(this, "Graph Size", 1){
container = [];
input( type: "bool", name: "graph_static_size", title: "Set size of Graph?
(False = Fill Window)", defaultValue: false, submitOnChange: true);
if (graph_static_size==true){
container << parent.hubiForm_slider (this, title: "Horizontal dimension of the graph", name: "graph_h_size", default_value: 800, min: 100, max: 3000, units: " pixels", submit_on_change: false);
container << parent.hubiForm_slider (this, title: "Vertical dimension of the graph", name: "graph_v_size", default_value: 600, min: 100, max: 3000, units: " pixels", submit_on_change: false);
}
parent.hubiForm_container(this, container, 1);
}
parent.hubiForm_section(this, "Annotations", 1){
container = [];
container << parent.hubiForm_font_size (this, title: "Annotation", name: "annotation", default: 16, min: 2, max: 40);
container << parent.hubiForm_switch (this, title: "Show Annotation Outside (true) or Inside (false) of Bars", name: "annotation_inside", default: false);
container << parent.hubiForm_color (this, "Annotation", "annotation", "#000000", false);
container << parent.hubiForm_color (this, "Annotation Aura", "annotation_aura", "#FFFFFF", false);
container << parent.hubiForm_switch (this, title: "Bold Annotation", name: "annotation_bold", default: false);
container << parent.hubiForm_switch (this, title: "Italic Annotation", name: "annotation_italic", default: false);
parent.hubiForm_container(this, container, 1);
}
}
}
def disableAPIPage() {
dynamicPage(name: "disableAPIPage") {
section() {
if (state.endpoint) {
try {
revokeAccessToken();
}
catch (e) {
log.debug "Unable to revoke access token: $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, "Select Device/Data", "deviceSelectionPage", "100%", "vibration");
container << parent.hubiForm_page_button(this, "Configure Graph", "graphSetupPage", "100%", "poll");
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 (graph_timespan){
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 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 Bar Graph", "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 getTableRow3(col1, col2, col3){
def html = "