Giter Site home page Giter Site logo

webcore's People

Contributors

acd37 avatar adey avatar ady624 avatar bjones14 avatar bloodtick avatar chauger avatar idpaterson avatar imnotbob avatar tbam avatar tyron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webcore's Issues

three axis for smart things contact sensor JSON error

This week my garage door sensor based pistons stopped working. It looks like there is a json error happening. the error is:
An error occurred while executing the event: groovy.json.JsonException: A JSON payload should start with an openning curly brace '{' or an openning square bracket ''. Instead, '1577' was found on line: 1, column: 1

1577 is the value of the sensors X axis.
download

\" in text variable get transformed with '

Whether in a variable or an expression, double quotes get replaced by single quotes resulting in invalid JSON when trying to pass

[ "presence", "webcore", "smartthings","Erik"]

in a make web request (POST).

I think it should simply get escaped to " instead of replaced with '

webcore_dashboard

Add ability to use textToSpeech

Devices such as the new local Sonos integration no longer include the custom capability playText and its derivatives. As devices more move to local execution such as the new Sonos they no longer have access to the TTS cloud service required to generate the TTS sounds. The solution to this problem is to have the SmartApp use the textToSpeech API as seen here in BigTalker:

https://github.com/rayzurbock/SmartThings-BigTalker-Orig/blob/db50483c97dab7ff92c3ada9232814b8e38b4d27/BigTalker.groovy#L2969

Once the sounds is generated it can then be sent to any capability that can play a url. For Sonos and most other the speakers this would be the Audio Notification capability.

Supporting this in WebCore will enable it to again play TTS sounds to Sonos and future local speakers from pistons.

Piston fails to load in browser to view and edit

Approx. 21:30 BST I was attempting to edit a piston and received the error message 'Sorry, an error occurred while retrieving the piston data' Only option is to click 'Go home'. Other pistons open fine.
Is there anyway to retrieve the piston?

Checking the live log, I am getting the following error...
physicalgraph.exception.StateCharacterLimitExceededException: State cannot be greater than 100000.0 characters @ line 792
Assume I've over done it?!

I have tried to create a copy by creating a new piston from this one, but the resulting piston is empty, same issues I would imagine :(
If I can't get it back (it appears to still be running), is there a way to delete it and start again?

webcore forum innacessible?

Hello,

I have been trying to sign up for the webcore forum but no matter what I try (2 different browsers, fill all fields/only some/...), the sign up button remains greyed out.

is this normal?

screen shot 2017-10-01 at 3 09 02 pm

Array index 0 inaccessible in for-loop

I setup an array of integers and try to access them in a for loop. On the first iteration using $index, the array[0] returns 0 (or null if I log it alone without strings) no matter what. I can access array[0] without using index variable.

Example:
arraytestpiston

9/14/2017, 7:48:24 AM +34ms

+374ms | ║index: 0; array: 0
+417ms | ║index: 1; array: 79
+456ms | ║index: 2; array: 77
+503ms | ║array[0]: 81; array[1]: 79; array[2] 77

Request: allow pistons to create external image from text

This is specifically to support ActionTiles which has limited to no capability to show any data from WebCoRE unless it is via a SmartThings supported device. ActionTiles does have capability to show images.

Request a way to add text to an image. Maybe each piston could have an 'external image' URL similar to the piston external URL. The new URL would return GIF or PNG(???) image as created by the piston new text2image commands. Some options to control font size would be useful as well (title larger font, footer info small font etc).

WebCore tiles are oviously very similar, so maybe they could be extended to provide an external image URL.

ImageMagick comes up frequently when searching net for 'adding text to image' Some possibly useful (???) resources....

http://im4java.sourceforge.net/

https://stackoverflow.com/questions/1636913/which-java-groovy-library-to-overlay-text-on-an-image

https://stackoverflow.com/questions/18800717/convert-text-content-to-image

UI Development and Dashboard

Hey guys, I'm liking the platform and have been thinking about building a separate reporting UI to start interacting with WebCoRE and graphing the data. However, after some thought, it seems pretty pointless if I can just contribute to this and build something up that everyone can benefit from.
Is it at all possible to contribute to this and any help getting something set up locally would be great :)

Filtered subscriptions

I notice several of my pistons run when they don't actually need to. This may just be a limitation of SmartThings and event subscriptions, but there are a wide variety of events which can be referenced in a piston which don't need to be subscribed to 24/7. They basically boil down to patterns of A && B && C; if A is currently false, events from B and C are irrelevant and can be ignored. (For example, my logs are filled with motion sensor triggers by my cats while the location is in a mode that doesn't actually do anything when motion is detected.)

(Events of the type "rises above" or "stays" do this too, though that seems somewhat unavoidable. They might be handled in a layer above the piston, but something still has to run enough to see whether the condition has returned to a state where the event can take place in the future.)

Issue with integer comparison in switch

This stopped working after a recent update/publish. You can see in the logs & the screenshot that there is an apparent bug when comparing integers: "Comparison (integer) 1 is (integer) 1 = false (3ms)"
image

Which refers to the switch statement below:

image

Timer warning

The new timer warning is appearing on any timer event, even top level statements.

was_greater_than issue?

Hello,

I have been trying to port my pistons from Core to Webcore. Most work, however I cannot get the device power readings to work correctly. See below

The condition I have is:

Washing Machine's power was greater than 10W for 1min

this evaluates to (in the log):

Comparison (decimal) 16.3 was_greater_than (decimal) 10.0 = false (42ms)

Which should evaluate to true, not false.

Any help appreciated.

screen shot 2017-10-01 at 2 49 28 pm

You don't have access to ady624/webCoRE

I accidentally deleted the WebCoRE smartApp from Smartthings IDE. When I went back to try and add it back in through the settings button, I received the subject error message. I researched through the issues section and noted that a similar issue was resolved by logging out of github and then logging back in. This did not resolve the issue in my case.
smartapps1
smartapps2

Support Event Subscriptions on Global Variables

Right now, local variables with devices will create subscriptions correctly. However, global variables do not create subscriptions properly despite showing the lightning bolt icon.

Note how the lightning icon is present in the code view, but the yellow warning is still present and the list of subscriptions is empty.

List type globals

I noticed that it is possible to create lists for local variables but not for globals. I am not sure if this is by design or an oversight, but I thought I'd mention it.

Error greater than or equal to

I realize you are still in alpha. I just wanted to let you know of issue i was seeing in testing.
Error calling comparison comp_stays_greater_than_or_equal_to: groovy.lang.MissingMethodException: No signature of method: script1491876398496636377990.comp_stays_greater_than_or_equal_to() is applicable for argument types: (java.util.LinkedHashMap, java.util.LinkedHashMap, java.util.LinkedHashMap) values: [[logging:[error:true, warn:true, info:true, ...], ...], ...]

disable or warn about backup feature not working

I used it before deleting my webCoRE installation and lost all of my pistons as there's no way to restore from the backup file currently.

Disabling or displaying a warning would be sweet for users.

Thanks for the awesome project!

Potential naming conflict.

Howdy!

I'm the maintainer of the Python WebCore web framework (see the master branch commit history) and got a neat Google Alert regarding a forum question about your webCoRE project. My WebCore project has been in production use since 2009. Your package is quite new—Nov 2016 repo, March 2017 wiki—and documentation (wiki, etc.) inconsistent in the application of capitalization to your product name, often referred to as simply webcore or webCore.

  1. Unfortunately, packages under most package management systems do not use Github account prefixes. For example, Gentoo ebuilds or RedHat / Ubuntu /Debian packages.

  2. It pollutes internet searches for the term with multiple competing web development software packages (common problem domain); the WebCore web framework is currently ranked 2nd on Duckduckgo (better for testing as it doesn't personalize result ordering; this up from 4th in early March, 2016, ref: stentle/laravel-web-core#1) and is mixed with Apple's WebKit results, because Apple's internal API naming conventions. (ImageCore, TextCore, … ;)

Having dug a bit into what you're doing, I love the idea of your project; I've been progressively automating things at home for the last year or so. Nothing quite as magical as arriving home and having a dozen things happen automatically, locks unlock, lights switch, TV says "hi". (Stretching it a bit on the last, of course…) What shall we do about this potential conflict, if anything? :)

Have a great day,
— Alice.

Improve logging or label condition numbers

Hi,

I'm trying to debug an issue with a piston and can't figure out which condition is triggering the command:

5/18/2017, 1:55:32 PM +352ms
+1ms	╔Received event Home].time = 1495140932896 with a delay of -545ms
+360ms	║RunTime Analysis CS > 130ms > PS > 95ms > PE > 135ms > CE
+375ms	║Runtime (33150 bytes) successfully initialized in 95ms (v0.1.0a7.20170515) (374ms)
+377ms	║╔Execution stage started
+475ms	║║Condition #15 evaluated true (1ms)
+477ms	║║Condition group #7 evaluated true (changed) (15ms)
+515ms	║║Executed physical command Garage Light Switch].off() (29ms)
+516ms	║║Executed Garage Light Switch].off (33ms)
+827ms	║║Fast executing schedules, waiting for 563ms to sync up
+1418ms	║║Condition #15 evaluated true (1ms)
+1419ms	║║Condition group #7 evaluated true (did not change) (6ms)
+1446ms	║║Executed physical command Garage Light Switch].off() (21ms)
+1447ms	║║Executed Garage Light Switch].off (23ms)
+1660ms	║║Fast executing schedules, waiting for 1040ms to sync up
+2740ms	║║Condition #15 evaluated true (3ms)
+2743ms	║║Condition group #7 evaluated true (did not change) (9ms)
+2767ms	║║Executed physical command Garage Light Switch].off() (16ms)
+2768ms	║║Executed Garage Light Switch].off (18ms)
+3050ms	║╚Execution stage complete. (2673ms)
+3145ms	║Setting up scheduled job for Thu, May 18 2017 @ 1:58:34 PM PDT (in 179.5s), with 5 more jobs pending
+3173ms	╚Event processed successfully (3174ms)

I think what would help is if you added a text representation of the condition or label the conditions in the editor.

Thanks,

Matt

Web Requests Fail

Getting the following error in webCore with web requests. I've also requested a wiki account so I can add this to the todo list

║Error executing virtual command [].httpRequest: (1ms) groovy.lang.MissingMethodException: No signature of method: script14921351763651536110737.vcmd_httpRequest() is applicable for argument types: (java.util.LinkedHashMap, java.util.ArrayList, java.util.ArrayList) values: [[logging:[error:true, warn:true, info:true, ...], ...], ...]

Request: Add variable to reflect SHM intrusion status

I think that having a variable that can be observed / listened to that tells whether SHM has detected an intrusion / had the intrusion dismissed would be very useful.

One of my use cases is turning on interior cameras when an intrusion is detected during 'Armed/Stay', then turning them off once the intrusion is dismissed.

I can look into adding this if you're interested / can point me in the right direction.

"Changes to" missing a lot of events, "On Event" is perfect.

When using "Changes to" as a trigger, it misses a lot of events. This has been verified by another forum member. However "On Event" works 100%. Seems to miss ~35% of events.

I created 3 pistons.

Testing - Changes To (import code: wdt3)
This piston increments a variable each time a virtual momentary button gets pressed. It detected it being pressed by using "Changes To".

image

Testing - On Event (import code: ciwc)
This piston increments a variable each time a virtual momentary button gets pressed. It detected it being pressed by using "On Event" then checks the variable "$currentEventValue" to see if it is "on".

image

Testing - Push (import code: n66h)
Pushes the virtual button every 30 seconds.

image

It didn't take long for the "Changes To" piston to miss events. After 10 minutes it missed 8 events.

image

When it missed the events it had this in the logs... Notice that "changes_to on" evaluates to false.

5/26/2017, 6:29:08 PM +583ms
+1ms	╔Received event [Test Button].switch = on with a delay of 30ms
+210ms	║RunTime Analysis CS > 18ms > PS > 177ms > PE > 15ms > CE
+223ms	║Runtime (31439 bytes) successfully initialized in 177ms (v0.1.0b1.20170524) (220ms)
+225ms	║╔Execution stage started
+385ms	║║Comparison on changes_to on = false (1ms)
+387ms	║║Condition #6 evaluated false (10ms)
+388ms	║║Condition group #1 evaluated false (state did not change) (13ms)
+428ms	║╚Execution stage complete. (203ms)
+444ms	╚Event processed successfully (444ms)


5/26/2017, 6:29:08 PM +614ms
+2ms	╔Received event [Test Button].switch = off with a delay of 56ms
+182ms	║RunTime Analysis CS > 21ms > PS > 147ms > PE > 14ms > CE
+194ms	║Runtime (31440 bytes) successfully initialized in 147ms (v0.1.0b1.20170524) (192ms)
+195ms	║╔Execution stage started
+211ms	║║Comparison off changes_to on = false (1ms)
+213ms	║║Condition #6 evaluated false (8ms)

After 2 hours...

image

After a long time...

image

Forum Post: https://community.smartthings.com/t/private-webcore-momma-wants-grandkids-channel-6/87598/589?u=whoismoses

Can't open on chrome

I am trying to send the url from my iphone to my Mac and I get this message

Oops, you are not logged in!

Please open the SmartThings IDE, go to Live Logging, then open the SmartThings CoRE app and look for the dashboard URL in the Live Logging page. You will need to open that link for the first time.

If I follow these instructions my log view for webCoRE is blank.

Routine

Hi ,

If i run a routine it will not trigger the action on webcore it did work always before

Attribute button only displays `gets` as a trigger

Possibly a bug, for the button attribute it only shows gets as a trigger. For other attributes it shows a whole host of triggers.

This limits the way the button devices can be used since buttons are often held which means they will continue to show held as the status until they are released and the piston should be able to use the current status of a button in a if condition when triggered by another device.

e.g. keep holding the button which triggers a volume increase which triggers the piston which checks if the button is still held and then increases the volume and this continues in a loop into until the button is released.

Ideally it should show the same triggers as any other attribute (e.g. switch or alarm).

Bug? Global variables with type = time

I have a simple piston that turns on my lights if certain conditions are met + TIME is between 2 global variables (variables type = time). Piston code -> 49neg

image

The thing is, when the piston checks the is between condition, it returns false because 1 of the global variables has the year 1970...

Comparison 66708334 is_between 1970-01-01T16:00:00.000Z .. 2017-07-10T01:00:00.000Z = false (14ms)

Those are the values, in local time of my global variables used with this piston:

image

Any ideas of why the global variable gets set with the year 1970 and how to fix this?

Tks vm and congrats for the project, it is amazing!!

Pistons fail when device goes missing

I had some z-wave issues with my ST hub last week, and it looks (I do not know how to recover older logs) like any pistons that contained devices that were flakey threw some sort of NPE and failed.

I am just recovering from this with the day off today, so I can not reproduce nor paste in logs.

In the pistons in question, the failing devices' names were replaced with a numeric ID - that's how it lead me to believe this is what is happening.

Sorry I do not have better diagnostics on this.

Seems like the desired behavior would be the piston skipping the devices that do not resolve to anything real, but doing its best to complete the other actions.

What about the new Smartthings app?

Are there any plans related to the new Smartthings app? They'll deprecate the classic app eventually and even if they offer a rules engine in the new app, there is always going to be things that are missing or that don't work the way the users want. Also, Samsung bringing all the devices under one roof, could give WebCore even more power.

Btw, thank you for all the hard work. Thanks to you everything (literally) in my house is automated :).

"Metadata Error: Parent SmartApp 'stephack:ABC Manager' not found"

After creating /Publishing the Parent SmartApp (My Device Handler) , we attempt to create the Child SmartApp (My SmartApp) and observe this error -?-

Is there any obvious issues, or is there a method of troubleshot and verify that the syntax is correctly written, that can be recommended /thz -?-

Parent SmartApp
/*

  • Advanced Button Controller (Parent/Child Version)
  • Author: Stephan Hackett
  • 6/20/17 - fixed missing subs for notifications
  • 1/07/18 - split smartApp into Parent/Child (IOS hanging on intial startup) - requires complete uninstall and reinstall of Parent and child SmartApps
  • 1/14/18a - updated version check code
    */

definition(
name: "ABC Manager",
namespace: "stephack",
singleInstance: true,
author: "Stephan Hackett",
description: "Configure devices with buttons like the Aeon Labs Minimote and Lutron Pico Remotes.",
category: "My Apps",
iconUrl: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/abcNew.png",
iconX2Url: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/abcNew.png",
iconX3Url: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/abcNew.png",
)

preferences {
page(name: "mainPage")
page(name: "aboutPage")

}

def mainPage() {
return dynamicPage(name: "mainPage", title: "", install: true, uninstall: true) {
def childApps = getAllChildApps()
def childVer = "InitialSetup"
if(childApps.size() > 0) {
childVer = childApps.first().version()
}
section("Create a new button device mapping.") {
app(name: "childApps", appName: "ABC Child Creator", namespace: "stephack", title: "New Button Device Mapping", multiple: true)
}
section("Version Info, User's Guide") {
href (name: "aboutPage", title: "Advanced Button Controller \n"+childVer,
description: "Tap to get Smartapp Info and User's Guide.",
image: verImgCheck(childVer), required: false, // check repo for image that matches current version. Displays update icon if missing
page: "aboutPage"
)
}
remove("Uninstall ABC App","WARNING!!","This will remove the ENTIRE SmartApp, including all configs listed above.")
}
}

def verImgCheck(childVer){
def params = [
uri: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/abc_${childVer}.png",
]
try {
httpGet(params) { resp ->
resp.headers.each {
//log.debug "${it.name} : ${it.value}"
}
log.debug "ABC appears to be running the latest Version"
return params.uri
}
} catch (e) {
log.error "ABC does not appear to be the latest version: Please update from IDE"
return "https://cdn.rawgit.com/stephack/ABC/master/resources/images/update.png"
}
}

def installed() {
initialize()
}

def updated() {
unsubscribe()
initialize()
}

def initialize() {

}

private def textHelp() {
def text =
section("User's Guide - Advanced Button Controller") {
paragraph "This smartapp allows you to use a device with buttons including, but not limited to:\n\n Aeon Labs Minimotes\n"+
" HomeSeer HS-WD100+ switches**\n HomeSeer HS-WS100+ switches\n Lutron Picos***\n\n"+
"It is a heavily modified version of @DaleC's 'Button Controller Plus' which is in turn"+
" a version of @bravenel's 'Button Controller+'."
}
section("Some of the included changes are:"){
paragraph "A complete revamp of the configuration flow. You can now tell at a glance, what has been configured for each button."+
"The button configuration page has been collapsed by default for easier navigation."
paragraph "The original apps were hardcoded to allow configuring 4 or 6 button devices."+
" This app will automatically detect the number of buttons on your device or allow you to manually"+
" specify (only needed if device does not report on its own)."
paragraph "Allows you to give your buton device full speaker control including: Play/Pause, NextTrack, Mute, VolumeUp/Down."+
"(***Standard Pico remotes can be converted to Audio Picos)\n\nThe additional control options have been highlighted below."
}
section("Available Control Options are:"){
paragraph " Switches - Toggle \n"+
" Switches - Turn On \n"+
" Switches - Turn Off \n"+
" Dimmers - Toggle \n"+
" Dimmers - Set Level (Group 1) \n"+
" Dimmers - Set Level (Group 2) \n"+
" *Dimmers - Inc Level \n"+
" Dimmers - Dec Level \n"+
" Fans - Low, Medium, High, Off \n"+
" Shades - Up, Down, or Stop \n"+
" Locks - Unlock Only \n"+
" Speaker - Play/Pause \n"+
" Speaker - Next Track \n"+
" Speaker - Mute/Unmute \n"+
" Speaker - Volume Up \n"+
" Speaker - Volume Down \n"+
" Set Modes \n"+
" Run Routines \n"+
" Sirens - Toggle \n"+
" Push Notifications \n"+
" SMS Notifications"
}
section ("
Quirk for HS-WD100+ on Button 5 & 6:"){
paragraph "Because a dimmer switch already uses Press&Hold to manually set the dimming level"+
" please be aware of this operational behavior. If you only want to manually change"+
" the dim level to the lights that are wired to the switch, you will automatically"+
" trigger the 5/6 button event as well. And the same is true in reverse. If you"+
" only want to trigger a 5/6 button event action with Press&Hold, you will be manually"+
" changing the dim level of the switch simultaneously as well.\n"+
"This quirk doesn't exist of course with the HS-HS100+ since it is not a dimmer."
}
section("
Lutron Pico Requirements:"){
paragraph "Lutron Picos are not natively supported by SmartThings. A Lutron SmartBridge Pro, a device running @njschwartz's python script (or node.js) and the Lutron Caseta Service Manager"+
" SmartApp are also required for this functionality!\nSearch the forums for details."
}
}

Child SmartApp
/* DO NOT PUBLISH !!!!
*

  • Child Creator - Advanced Button Controller
  • Author: SmartThings, modified by Bruce Ravenel, Dale Coffing, Stephan Hackett
  • 6/20/17 - fixed missing subs for notifications
  • 1/14/18 - updated Version check code
  • 1/15/18 - added icon support for Inovelli Switches (NZW30S and NZW31S)
  •     - small adjustments to "Configure Button" page layout
    
  • DO NOT PUBLISH !!!!
    */
    def version(){"v0.2.180115"}

definition(
name: "ABC Child Creator",
namespace: "stephack",
author: "Stephan Hackett",
description: "SHOULD NOT BE PUBLISHED",
category: "My Apps",
parent: "stephack:ABC Manager",
iconUrl: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/abcNew.png",
iconX2Url: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/abcNew.png",
iconX3Url: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/abcNew.png",
)

preferences {
page(name: "chooseButton")
page(name: "configButtonsPage")
page(name: "timeIntervalInput", title: "Only during a certain time") {
section {
input "starting", "time", title: "Starting", required: false
input "ending", "time", title: "Ending", required: false
}
}
}

def chooseButton() {
dynamicPage(name: "chooseButton", install: true, uninstall: true) {
section("Step 1: Select Your Button Device") {
input "buttonDevice", "capability.button", title: "Button Device", multiple: false, required: true, submitOnChange: true
}
if(buttonDevice){
state.buttonType = buttonDevice.typeName
if(state.buttonType.contains("Aeon Minimote")) state.buttonType = "Aeon Minimote"
log.debug "Device Type is now set to: "+state.buttonType
state.buttonCount = manualCount?: buttonDevice.currentValue('numberOfButtons')
//if(state.buttonCount==null) state.buttonCount = buttonDevice.currentValue('numButtons') //added for kyse minimote(hopefully will be updated to correct attribute name)
section("Step 2: Configure Your Buttons"){
if(state.buttonCount<1) {
paragraph "The selected button device did not report the number of buttons it has. Please specify in the Advanced Config section below."
}
else {
for(i in 1..state.buttonCount){
href "configButtonsPage", title: "Button ${i} - (Tap to Edit)", description: getDescription(i), params: [pbutton: i]
}
}
}
}
section("Set Custom Name (Optional)") {
label title: "Assign a name:", required: false
}
section("Advanced Config:", hideable: true, hidden: hideOptionsSection()) {
input "manualCount", "number", title: "Set/Override # of Buttons?", required: false, description: "Only set if DTH does not report", submitOnChange: true
input "collapseAll", "bool", title: "Collapse Unconfigured Sections?", defaultValue: true
input "hwSpecifics", "bool", title: "Hide H/W Specific Details?", defaultValue: false
}
section(title: "Only Execute When:", hideable: true, hidden: hideOptionsSection()) {
def timeLabel = timeIntervalLabel()
href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : null
input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
input "modes", "mode", title: "Only when mode is", multiple: true, required: false
}
}
}

def configButtonsPage(params) {
if (params.pbutton != null) state.currentButton = params.pbutton.toInteger()
dynamicPage(name: "configButtonsPage", title: "CONFIGURE BUTTON ${state.currentButton}:\n${state.buttonType}", getButtonSections(state.currentButton))
}

def getButtonSections(buttonNumber) {
return {
def picNameNoSpace = "${state.buttonType}${state.currentButton}.png"-" "-" "-" "-"/"
//log.debug picNameNoSpace
section(){ //"Hardware specific info on button selection:") {
if(hwSpecifics== false) paragraph image: "https://cdn.rawgit.com/stephack/ABC/master/resources/images/${picNameNoSpace}", "${getSpecText()}"
}
section("Switches (Turn On)", hideable: true, hidden: !shallHide("lightOn_${buttonNumber}")) {
input "lightOn_${buttonNumber}pushed", "capability.switch", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "lightOn
${buttonNumber}held", "capability.switch", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section("Switches (Turn Off)", hideable: true, hidden: !shallHide("lightOff
${buttonNumber}")) {
input "lightOff_${buttonNumber}pushed", "capability.switch", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "lightOff
${buttonNumber}held", "capability.switch", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section("Switches (Toggle On/Off)", hideable: true, hidden: !shallHide("lights
${buttonNumber}")) {
input "lights_${buttonNumber}pushed", "capability.switch", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "lights
${buttonNumber}held", "capability.switch", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section(" "){}
section("Dimmers (On to Level - Group 1)", hideable: true, hidden: !(shallHide("lightDim
${buttonNumber}") || shallHide("valLight${buttonNumber}"))) {
input "lightDim_${buttonNumber}pushed", "capability.switchLevel", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
input "valLight${buttonNumber}pushed", "number", title: "Bright Level", multiple: false, required: false, description: "0 to 100%"
if(showHeld()) input "lightDim
${buttonNumber}held", "capability.switchLevel", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "valLight${buttonNumber}held", "number", title: "Bright Level", multiple: false, required: false, description: "0 to 100%"
}
section("Dimmers (On to Level - Group 2)", hideable: true, hidden: !(shallHide("lightD2m
${buttonNumber}") || shallHide("valLight2${buttonNumber}"))) {
input "lightD2m
${buttonNumber}pushed", "capability.switchLevel", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
input "valLight2${buttonNumber}pushed", "number", title: "Bright Level", multiple: false, required: false, description: "0 to 100%"
if(showHeld()) input "lightD2m
${buttonNumber}held", "capability.switchLevel", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "valLight2${buttonNumber}held", "number", title: "Bright Level", multiple: false, required: false, description: "0 to 100%"
}
section("Dimmers (Increase Level By)", hideable: true, hidden: !(shallHide("dimPlus
${buttonNumber}") || shallHide("valDimP${buttonNumber}"))) {
input "dimPlus
${buttonNumber}pushed", "capability.switchLevel", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
input "valDimP${buttonNumber}pushed", "number", title: "When Pushed Increase by", multiple: false, required: false, description: "0 to 15"
if(showHeld()) input "dimPlus
${buttonNumber}held", "capability.switchLevel", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "valDimP${buttonNumber}held", "number", title: "When Held Increase by", multiple: false, required: false, description: "0 to 15"
}
section("Dimmers (Decrease Level By)", hideable: true, hidden: !(shallHide("dimMinus
${buttonNumber}") || shallHide("valDimM${buttonNumber}"))) {
input "dimMinus
${buttonNumber}pushed", "capability.switchLevel", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
input "valDimM${buttonNumber}pushed", "number", title: "When Pushed Decrease by", multiple: false, required: false, description: "0 to 15"
if(showHeld()) input "dimMinus
${buttonNumber}held", "capability.switchLevel", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "valDimM${buttonNumber}held", "number", title: "When Held Decrease by", multiple: false, required: false, description: "0 to 15"
}
section("Dimmers (Toggle OnToLevel/Off)", hideable: true, hidden: !(shallHide("lightsDT
${buttonNumber}") || shallHide("valDT${buttonNumber}"))) {
input "lightsDT
${buttonNumber}pushed", "capability.switchLevel", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
input "valDT${buttonNumber}pushed", "number", title: "Bright Level", required: false, description: "0 to 100%"
if(showHeld()) input "lightsDT
${buttonNumber}held", "capability.switchLevel", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "valDT${buttonNumber}held", "number", title: "Bright Level", required: false, description: "0 to 100%"
}
section(" "){}
section("Speakers (Toggle Play/Pause)", hideable: true, hidden: !shallHide("speakerpp
${buttonNumber}")) {
input "speakerpp
${buttonNumber}pushed", "capability.musicPlayer", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "speakerpp
${buttonNumber}held", "capability.musicPlayer", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section("Speakers (Increase Vol By)", hideable: true, hidden: !(shallHide("speakervu
${buttonNumber}") || shallHide("valSpeakU${buttonNumber}"))) {
input "speakervu
${buttonNumber}pushed", "capability.musicPlayer", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
input "valSpeakU${buttonNumber}pushed", "number", title: "When Pushed Increase by", multiple: false, required: false, description: "0 to 15"
if(showHeld()) input "speakervu
${buttonNumber}held", "capability.musicPlayer", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "valSpeakU${buttonNumber}held", "number", title: "When Held Increase by", multiple: false, required: false, description: "0 to 15"
}
section("Speakers (Decrease Vol By)", hideable: true, hidden: !(shallHide("speakervd
${buttonNumber}") || shallHide("valSpeakD${buttonNumber}"))) {
input "speakervd
${buttonNumber}pushed", "capability.musicPlayer", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
input "valSpeakD${buttonNumber}pushed", "number", title: "When Pushed Decrease by", multiple: false, required: false, description: "0 to 15"
if(showHeld())input "speakervd
${buttonNumber}held", "capability.musicPlayer", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld())input "valSpeakD${buttonNumber}held", "number", title: "When Held Decrease by", multiple: false, required: false, description: "0 to 15"
}
section("Speakers (Go to Next Track)", hideable: true, hidden: !shallHide("speakernt
${buttonNumber}")) {
input "speakernt
${buttonNumber}pushed", "capability.musicPlayer", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "speakernt
${buttonNumber}held", "capability.musicPlayer", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section("Speakers (Toggle Mute/Unmute)", hideable: true, hidden: !shallHide("speakermu
${buttonNumber}")) {
input "speakermu
${buttonNumber}pushed", "capability.musicPlayer", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "speakermu
${buttonNumber}held", "capability.musicPlayer", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section(" "){}
section("Sirens (Toggle)", hideable: true, hidden: !shallHide("sirens
${buttonNumber}")) {
input "sirens
${buttonNumber}pushed","capability.alarm" ,title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "sirens
${buttonNumber}held", "capability.alarm", title: "When Held", multiple: true, required: false, submitOnChange: true
}
section("Locks (Lock Only)", hideable: true, hidden: !shallHide("locks
${buttonNumber}")) {
input "locks
${buttonNumber}pushed", "capability.lock", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "locks
${buttonNumber}held", "capability.lock", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section("Fans (Adjust - Low, Medium, High, Off)", hideable: true, hidden: !shallHide("fanAdjust
${buttonNumber}")) {
input "fanAdjust
${buttonNumber}pushed", "capability.switchLevel", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "fanAdjust
${buttonNumber}held", "capability.switchLevel", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section("Shades (Adjust - Up, Down, or Stop)", hideable: true, hidden: !shallHide("shadeAdjust
${buttonNumber}")) {
input "shadeAdjust
${buttonNumber}pushed", "capability.doorControl", title: "When Pushed", multiple: true, required: false, submitOnChange: collapseAll
if(showHeld()) input "shadeAdjust
${buttonNumber}held", "capability.doorControl", title: "When Held", multiple: true, required: false, submitOnChange: collapseAll
}
section(" "){}
section("Set Mode", hideable: true, hidden: !shallHide("mode
${buttonNumber}")) {
input "mode
${buttonNumber}pushed", "mode", title: "When Pushed", required: false, submitOnChange: collapseAll
if(showHeld())input "mode
${buttonNumber}held", "mode", title: "When Held", required: false, submitOnChange: collapseAll
}
def phrases = location.helloHome?.getPhrases()*.label
if (phrases) {
section("Run Routine", hideable: true, hidden: !shallHide("phrase
${buttonNumber}")) {
//log.trace phrases
input "phrase_${buttonNumber}pushed", "enum", title: "When Pushed", required: false, options: phrases, submitOnChange: collapseAll
if(showHeld()) input "phrase
${buttonNumber}held", "enum", title: "When Held", required: false, options: phrases, submitOnChange: collapseAll
}
}
section("Notifications:\nSMS, In App or Both", hideable: true, hidden: !shallHide("notifications
${buttonNumber}")) {
paragraph "\nWHEN PUSHED\n"
input "notifications_${buttonNumber}pushed", "text", title: "Message", description: "Enter message to send", required: false, submitOnChange: collapseAll
input "phone
${buttonNumber}_pushed","phone" ,title: "Send Text To", description: "Enter phone number", required: false, submitOnChange: collapseAll
input "valNotify${buttonNumber}pushed","bool" ,title: "Notify In App?", required: false, defaultValue: false, submitOnChange: collapseAll
if(showHeld()) paragraph "\nWHEN HELD\n"
if(showHeld()) input "notifications
${buttonNumber}held", "text", title: "Message", description: "Enter message to send", required: false, submitOnChange: collapseAll
if(showHeld()) input "phone
${buttonNumber}held", "phone", title: "Send Text To", description: "Enter phone number", required: false, submitOnChange: collapseAll
if(showHeld()) input "valNotify${buttonNumber}held", "bool", title: "Notify In App?", required: false, defaultValue: false, submitOnChange: collapseAll
}
if(enableSpec()){
section(" "){}
section("Special", hideable: true, hidden: !shallHide("container
${buttonNumber}")) {
input "container
${buttonNumber}pushed", "device.VirtualContainer", title: "When Pushed", required: false, submitOnChange: collapseAll
if(showHeld())input "container
${buttonNumber}_held", "device.VirtualContainer", title: "When Held", required: false, submitOnChange: collapseAll
}
}
}
}

def enableSpec() {
return false
}

def showHeld() {
if(state.buttonType.contains("100+ ")) return false
else return true
}

def shallHide(myFeature) {
if(collapseAll) return (settings["${myFeature}_pushed"]||settings["${myFeature}_held"]||settings["${myFeature}"])
return true
}

def getDescription(dNumber) {
def descript = "Nothing Configured"
def anySettings = settings.find{it.key.contains("${dNumber}")}
if(anySettings) descript = "PUSHED:"+getDescDetails(dNumber,"_pushed")+"\n\nHELD:"+getDescDetails(dNumber,"_held")//"CONFIGURED : Tap to edit"
return descript
}

def getDescDetails(bNum, type){
def numType=bNum+type
def preferenceNames = settings.findAll{it.key.contains("_${numType}")}.sort() //get all configured settings that: match button# and type, AND are not false
if(!preferenceNames){
return " Not Configured"
}
else {
def formattedPage =""
preferenceNames.each {eachPref->
def prefDetail = getPreferenceDetails().find{eachPref.key.contains(it.id)} //gets decription of action being performed(eg Turn On)
def prefDevice = " : ${eachPref.value}" - "[" - "]" //name of device the action is being performed on (eg Bedroom Fan)
def prefSubValue = settings[prefDetail.sub + numType]?:"(!Missing!)"
if(prefDetail.type=="normal") formattedPage += "\n- ${prefDetail.desc}${prefDevice}"
if(prefDetail.type=="hasSub") formattedPage += "\n- ${prefDetail.desc}${prefSubValue}${prefDevice}"
if(prefDetail.type=="bool") formattedPage += "\n- ${prefDetail.desc}"
}
return formattedPage
}
}

def installed() {
initialize()
}

def updated() {
unsubscribe()
initialize()
}

def initialize() {
log.debug "INITIALIZED with settings: ${settings}"
app.label==app.name?app.updateLabel(defaultLabel()):app.updateLabel(app.label)
subscribe(buttonDevice, "button", buttonEvent)
state.lastshadesUp = true
}

def defaultLabel() {
return "${buttonDevice} Mapping"
}

def getPreferenceDetails(){
def detailMappings =
[[id:'lights_',desc:'Toggle On/Off',comm:toggle, type:"normal"],
[id:'lightsDT_', desc:'Toggle Off/Dim to ', comm:dimToggle, sub:"valDT", type:"hasSub"],
[id:'lightOn_',desc:'Turn On ',comm:turnOn, type:"normal"],
[id:"lightOff_",desc:'Turn Off',comm:turnOff, type:"normal"],
[id:"lightDim_",desc:'Dim to ',comm:turnDim, sub:"valLight", type:"hasSub"],
[id:"lightD2m_",desc:'Dim to ',comm:turnDim, sub:"valLight2", type:"hasSub"],
[id:'dimPlus_',desc:'Brightness +',comm:levelUp, sub:"valDimP", type:"hasSub"],
[id:'dimMinus_',desc:'Brightness -',comm:levelDown, sub:"valDimM", type:"hasSub"],
[id:"fanAdjust_",desc:'Adjust',comm:adjustFan, type:"normal"],
[id:"shadeAdjust_",desc:'Adjust',comm:adjustShade, type:"normal"],
[id:"locks_",desc:'Lock',comm:setUnlock, type:"normal"],
[id:"speakerpp_",desc:'Toggle Play/Pause',comm:speakerplaystate, type:"normal"],
[id:'speakernt_',desc:'Next Track',comm:speakernexttrack, type:"normal"],
[id:'speakermu_',desc:'Mute',comm:speakermute, type:"normal"],
[id:'speakervu_',desc:'Volume +',comm:levelUp, sub:"valSpeakU", type:"hasSub"],
[id:"speakervd_",desc:'Volume -',comm:levelDown, sub:"valSpeakD", type:"hasSub"],
[id:"mode_",desc:'Set Mode',comm:changeMode, type:"normal"],
[id:"notifications_",desc:'Send Push Notification',comm:messageHandle, sub:"valNotify", type:"bool"],
[id:'sirens_',desc:'Toggle',comm:toggle, type:"normal"],
[id:"phone_",desc:'Send SMS',comm:smsHandle, sub:"notifications_", type:"normal"],
[id:"phrase_",desc:'Run Routine',comm:runRout, type:"normal"],
[id:"container_",desc:'Cycle Playlist',comm:cyclePL, type:"normal"],
]
return detailMappings
}

def buttonEvent(evt) {
if(allOk) {
def buttonNumber = evt.jsonData.buttonNumber
def pressType = evt.value
log.debug "$buttonDevice: Button $buttonNumber was $pressType"
def preferenceNames = settings.findAll{it.key.contains("${buttonNumber}${pressType}")}
preferenceNames.each{eachPref->
def prefDetail = getPreferenceDetails()?.find{eachPref.key.contains(it.id)} //returns the detail map of id,desc,comm,sub
def PrefSubValue = settings["${prefDetail.sub}${buttonNumber}_${pressType}"] //value of subsetting (eg 100)
if(prefDetail.sub) "$prefDetail.comm"(eachPref.value,PrefSubValue)
else "$prefDetail.comm"(eachPref.value)
}
}
}

def turnOn(devices) {
log.debug "Turning On: $devices"
devices.on()
}

def turnOff(devices) {
log.debug "Turning Off: $devices"
devices.off()
}

def turnDim(devices, level) {
log.debug "Dimming (to $level): $devices"
devices.setLevel(level)
}

def adjustFan(device) {
log.debug "Adjusting: $device"
def currentLevel = device.currentLevel
if(device.currentSwitch == 'off') device.setLevel(15)
else if (currentLevel < 34) device.setLevel(50)
else if (currentLevel < 67) device.setLevel(90)
else device.off()
}

def adjustShade(device) {
log.debug "Shades: $device = ${device.currentMotor} state.lastUP = $state.lastshadesUp"
if(device.currentMotor in ["up","down"]) {
state.lastshadesUp = device.currentMotor == "up"
device.stop()
} else {
state.lastshadesUp ? device.down() : device.up()
// if(state.lastshadesUp) device.down()
// else device.up()
state.lastshadesUp = !state.lastshadesUp
}
}

def speakerplaystate(device) {
log.debug "Toggling Play/Pause: $device"
device.currentValue('status').contains('playing')? device.pause() : device.play()
}

def speakernexttrack(device) {
log.debug "Next Track Sent to: $device"
device.nextTrack()
}

def speakermute(device) {
log.debug "Toggling Mute/Unmute: $device"
device.currentValue('mute').contains('unmuted')? device.mute() : device.unmute()
}

def levelUp(device, inclevel) {
log.debug "Incrementing Level (by +$inclevel: $device"
def currentVol = device.currentValue('level')[0] //currentlevel return a list...[0] is first item in list ie volume level
def newVol = currentVol + inclevel
device.setLevel(newVol)
log.debug "Level increased by $inclevel to $newVol"
}

def levelDown(device, declevel) {
log.debug "Decrementing Level (by -declevel: $device"
def currentVol = device.currentValue('level')[0]
def newVol = currentVol.toInteger()-declevel
device.setLevel(newVol)
log.debug "Level decreased by $declevel to $newVol"
}

def setUnlock(devices) {
log.debug "Locking: $devices"
devices.lock()
}

def toggle(devices) {
log.debug "Toggling: $devices"
if (devices*.currentValue('switch').contains('on')) {
devices.off()
}
else if (devices*.currentValue('switch').contains('off')) {
devices.on()
}
else if (devices*.currentValue('alarm').contains('off')) {
devices.siren()
}
else {
devices.on()
}
}

def dimToggle(devices, dimLevel) {
log.debug "Toggling On/Off | Dimming (to $dimLevel): $devices"
if (devices*.currentValue('switch').contains('on')) devices.off()
else devices.setLevel(dimLevel)
}

def runRout(rout){
log.debug "Running: $rout"
location.helloHome.execute(rout)
}

def messageHandle(msg, inApp) {
if(inApp==true) {
log.debug "Push notification sent"
sendPush(msg)
}
}

def smsHandle(phone, msg){
log.debug "SMS sent"
sendSms(phone, msg ?:"No custom text entered on: $app.label")
}

def changeMode(mode) {
log.debug "Changing Mode to: $mode"
if (location.mode != mode && location.modes?.find { it.name == mode }) setLocationMode(mode)
}

def cyclePL(device) {
//int currPL = device.currentValue('lastRun')
// int nextPL = currPL+1
device.cycleChild()
//device.on(nextPL)

}

// execution filter methods
private getAllOk() {
modeOk && daysOk && timeOk
}

private getModeOk() {
def result = !modes || modes.contains(location.mode)
log.trace "modeOk = $result"
result
}

private getDaysOk() {
def result = true
if (days) {
def df = new java.text.SimpleDateFormat("EEEE")
if (location.timeZone) {
df.setTimeZone(location.timeZone)
}
else {
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
}
def day = df.format(new Date())
result = days.contains(day)
}
log.trace "daysOk = $result"
result
}

private getTimeOk() {
def result = true
if (starting && ending) {
def currTime = now()
def start = timeToday(starting).time
def stop = timeToday(ending).time
result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
}
log.trace "timeOk = $result"
result
}

private hhmm(time, fmt = "h:mm a") {
def t = timeToday(time, location.timeZone)
def f = new java.text.SimpleDateFormat(fmt)
f.setTimeZone(location.timeZone ?: timeZone(time))
f.format(t)
}

private hideOptionsSection() {
(starting || ending || days || modes || manualCount) ? false : true
}

private timeIntervalLabel() {
(starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
}

private def textHelp() {
def text =
section("User's Guide - Advanced Button Controller") {
paragraph "This smartapp allows you to use a device with buttons including, but not limited to:\n\n Aeon Labs Minimotes\n"+
" HomeSeer HS-WD100+ switches**\n HomeSeer HS-WS100+ switches\n Lutron Picos***\n\n"+
"It is a heavily modified version of @DaleC's 'Button Controller Plus' which is in turn"+
" a version of @bravenel's 'Button Controller+'."
}
section("Some of the included changes are:"){
paragraph "A complete revamp of the configuration flow. You can now tell at a glance, what has been configured for each button."+
"The button configuration page has been collapsed by default for easier navigation."
paragraph "The original apps were hardcoded to allow configuring 4 or 6 button devices."+
" This app will automatically detect the number of buttons on your device or allow you to manually"+
" specify (only needed if device does not report on its own)."
paragraph "Allows you to give your buton device full speaker control including: Play/Pause, NextTrack, Mute, VolumeUp/Down."+
"(***Standard Pico remotes can be converted to Audio Picos)\n\nThe additional control options have been highlighted below."
}
section("Available Control Options are:"){
paragraph " Switches - Toggle \n"+
" Switches - Turn On \n"+
" Switches - Turn Off \n"+
" Dimmers - Toggle \n"+
" Dimmers - Set Level (Group 1) \n"+
" Dimmers - Set Level (Group 2) \n"+
" *Dimmers - Inc Level \n"+
" Dimmers - Dec Level \n"+
" Fans - Low, Medium, High, Off \n"+
" Shades - Up, Down, or Stop \n"+
" Locks - Unlock Only \n"+
" Speaker - Play/Pause \n"+
" Speaker - Next Track \n"+
" Speaker - Mute/Unmute \n"+
" Speaker - Volume Up \n"+
" Speaker - Volume Down \n"+
" Set Modes \n"+
" Run Routines \n"+
" Sirens - Toggle \n"+
" Push Notifications \n"+
" SMS Notifications"
}
section ("
Quirk for HS-WD100+ on Button 5 & 6:"){
paragraph "Because a dimmer switch already uses Press&Hold to manually set the dimming level"+
" please be aware of this operational behavior. If you only want to manually change"+
" the dim level to the lights that are wired to the switch, you will automatically"+
" trigger the 5/6 button event as well. And the same is true in reverse. If you"+
" only want to trigger a 5/6 button event action with Press&Hold, you will be manually"+
" changing the dim level of the switch simultaneously as well.\n"+
"This quirk doesn't exist of course with the HS-HS100+ since it is not a dimmer."
}
section("
Lutron Pico Requirements:"){
paragraph "Lutron Picos are not natively supported by SmartThings. A Lutron SmartBridge Pro, a device running @njschwartz's python script (or node.js) and the Lutron Caseta Service Manager"+
" SmartApp are also required for this functionality!\nSearch the forums for details."
}
}

def getSpecText(){
if(state.buttonType == "Lutron Pico") {
switch (state.currentButton){
case 1: return "Top Button"; break
case 2: return "Bottom Button"; break
case 3: return "Middle Button";break
case 4: return "Up Button"; break
case 5: return "Down Button"; break
}
}
if(state.buttonType.contains("Aeon Minimote")) {
switch (state.currentButton){
case 1: return "Top Left Button"; break
case 2: return "Top Right Button"; break
case 3: return "Lower Left Button";break
case 4: return "Lower Right"; break
}
}
if(state.buttonType.contains("WD100+ Dimmer")) {
switch (state.currentButton){
case 1: return "Double-Tap Upper Paddle"; break
case 2: return "Double-Tap Lower Paddle"; break
case 3: return "Triple-Tap Upper Paddle";break
case 4: return "Triple-Tap Lower Paddle"; break
case 5: return "Press & Hold Upper Paddle\n(See user guide for quirks)"; break
case 6: return "Press & Hold Lower Paddle\n(See user guide for quirks)"; break
case 7: return "Single Tap Upper Paddle\n(See user guide for quirks)"; break
case 8: return "Single Tap Lower Paddle\n(See user guide for quirks)"; break
}
}
if(state.buttonType.contains("WS100+ Switch")) {
switch (state.currentButton){
case 1: return "Double-Tap Upper Paddle"; break
case 2: return "Double-Tap Lower Paddle"; break
case 3: return "Triple-Tap Upper Paddle";break
case 4: return "Triple-Tap Lower Paddle"; break
case 5: return "Press & Hold Upper Paddle"; break
case 6: return "Press & Hold Lower Paddle"; break
case 7: return "Single Tap Upper Paddle";break
case 8: return "Single Tap Lower Paddle"; break
}
}
if(state.buttonType.contains("Inovelli")) {
switch (state.currentButton){
case 1: return "NOT OPERATIONAL - DO NOT USE"; break
case 2: return "2X Tap Upper Paddle = Pushed\n2X Tap Lower Paddle = Held"; break
case 3: return "3X Tap Upper Paddle = Pushed\n3X Tap Lower Paddle = Held"; break
case 4: return "4X Tap Upper Paddle = Pushed\n4X Tap Lower Paddle = Held";break
case 5: return "5X Tap Upper Paddle = Pushed\n5X Tap Lower Paddle = Held"; break
case 6: return "Hold Upper Paddle = Pushed\nHold Lower Paddle = Held"; break
}
}
return "Not Specified By Device"
}

/*FOR NEW INPUTS//////////////

  1. add input to config
  2. add info to detailMappings including subvalue if needed
  3. ensure correct type is used in map..or create a new one with its own formattedPage

FOR NEW BUTTON DEVICE TYPES///////////////

  1. ensure device reports buttonNumber
  2. if not, add sendEvent to DTH as needed OR just enter manually
  3. add any special instructions to getSpecText() using dth name
  4. create pics for each button using dthName+dNumber

*/

Is WebCore Down or has there been changes?

I am unable to add devices or even get into the settings. It spools and then bounces me back to the main page in the SmartApp for WebCore.

I am guessing it is a Samsung thing but wanted to inquire with you.

How to implement a tri-state switch?

So, I am getting up to speed on WebCoRE. What I am trying to do is create a tri-state switch for controlling my HVAC states (Cooling, Heating, off).

I thought I would create 3 virtual switches for each state, and when one is turned on it will turn off the others.

What I am not sure about how to do is can the actuating switch set the state of the other switches WITHOUT triggering the piston for that switch?

Does that make sense?

Improve alignment of "recent indicator" for multi-line pistons

Changing

td i[star] {	
	display: inline-block;
	color: #369;
	font-size: 8px;
	margin-top: -4px;
	padding: 0px 4px 0px 0px;
	vertical-align: middle;
}

to

td i[star] {	
	display: inline-block;
	color: #369;
	font-size: 8px;
	margin-top: -4px;
	padding: 1em 4px 0px 0px;
	vertical-align: top;
}

Keeps the blue dot (recent indicator) for the piston aligned with the piston name even if the piston state spans across multiple lines

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.