Code by Scott שאול בן ישוע
Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Sha'ul ben Yeshua
Hubitat Public Repo
Commits
1d4fa8a3
Verified
Commit
1d4fa8a3
authored
Oct 20, 2019
by
Sha'ul ben Yeshua
🎗
Browse files
porting to hubitat
parent
153b3d4e
Pipeline
#143
passed with stage
in 2 seconds
Changes
6
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
flow meter (fmi)/Consumption Metering/smartapp-consumption-child.groovy
0 → 100644
View file @
1d4fa8a3
/**
* Consumption Metering
*
* Copyright 2016 FortrezZ, LLC
*
* 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.
*
*/
definition
(
name:
"Consumption Metering"
,
namespace:
"FortrezZ"
,
author:
"FortrezZ, LLC"
,
description:
"Child SmartApp for Consumption Metering rules"
,
category:
"Green Living"
,
parent:
"FortrezZ:FortrezZ Water Consumption Metering"
,
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
{
page
(
name:
"prefsPage"
,
title:
"Plugin version 1.5\nChoose the detector behavior"
,
install:
true
,
uninstall:
true
)
// Do something here like update a message on the screen,
// or introduce more inputs. submitOnChange will refresh
// the page and allow the user to see the changes immediately.
// For example, you could prompt for the level of the dimmers
// if dimmers have been selected:
//log.debug "Child Settings: ${settings}"
}
def
prefsPage
()
{
def
dailySchedule
=
0
def
daysOfTheWeek
=
[
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
]
dynamicPage
(
name:
"prefsPage"
)
{
section
(
"Set Water Usage Goals"
)
{
input
(
name:
"type"
,
type:
"enum"
,
title:
"Set a new goal?"
,
submitOnChange:
true
,
options:
ruleTypes
())
}
def
measurementType
=
"water"
if
(
type
)
{
switch
(
type
)
{
case
"Daily Goal"
:
section
(
"Water Measurement Preference"
){
input
(
name:
"measurementType"
,
type:
"enum"
,
title:
"Press to change water measurement options"
,
submitOnChange:
true
,
options:
waterTypes
())}
section
(
"Threshold settings"
)
{
input
(
name:
"waterGoal"
,
type:
"decimal"
,
title:
"Daily ${measurementType} Goal"
,
required:
true
,
defaultValue:
0.5
)
}
break
case
"Weekly Goal"
:
section
(
"Water Measurement Preference"
){
input
(
name:
"measurementType"
,
type:
"enum"
,
title:
"Press to change water measurement options"
,
submitOnChange:
true
,
options:
waterTypes
())}
section
(
"Threshold settings"
)
{
input
(
name:
"waterGoal"
,
type:
"decimal"
,
title:
"Weekly ${measurementType} Goal"
,
required:
true
,
defaultValue:
0.1
)
}
break
case
"Monthly Goal"
:
section
(
"Water Measurement Preference"
){
input
(
name:
"measurementType"
,
type:
"enum"
,
title:
"Press to change water measurement options"
,
submitOnChange:
true
,
options:
waterTypes
())}
section
(
"Threshold settings"
)
{
input
(
name:
"waterGoal"
,
type:
"decimal"
,
title:
"Monthly ${measurementType} Goal"
,
required:
true
,
defaultValue:
0.1
)
}
break
default:
break
}
}
}
}
def
ruleTypes
()
{
def
types
=
[]
types
<<
"Daily Goal"
types
<<
"Weekly Goal"
types
<<
"Monthly Goal"
return
types
}
def
waterTypes
()
{
def
watertype
=
[]
watertype
<<
"Gallons"
watertype
<<
"Cubic Feet"
watertype
<<
"Liters"
watertype
<<
"Cubic Meters"
return
watertype
}
/*
def setDailyGoal(measurementType3)
{
return parent.setDailyGoal(measurementType3)
}
def setWeeklyGoal()
{
return parent.setWeeklyGoal(measurementType)
}
def setMonthlyGoal()
{
return parent.setMonthlyGoal(measurementType)
}
*/
def
actionTypes
()
{
def
types
=
[]
types
<<
[
name:
"Switch"
,
capability:
"capabilty.switch"
]
types
<<
[
name:
"Water Valve"
,
capability:
"capability.valve"
]
return
types
}
def
deviceCommands
(
dev
)
{
def
cmds
=
[]
dev
.
supportedCommands
.
each
{
command
->
cmds
<<
command
.
name
}
return
cmds
}
def
installed
()
{
state
.
Daily
=
0
log
.
debug
"Installed with settings: ${settings}"
app
.
updateLabel
(
"${type} - ${waterGoal} ${measurementType}"
)
//schedule(" 0 0/1 * 1/1 * ? *", setDailyGoal())
initialize
()
}
def
updated
()
{
log
.
debug
"Updated with settings: ${settings}"
app
.
updateLabel
(
"${type} - ${waterGoal} ${measurementType}"
)
unsubscribe
()
initialize
()
//unschedule()
}
def
settings
()
{
def
set
=
settings
if
(
set
[
"dev"
]
!=
null
)
{
log
.
debug
(
"dev set: ${set.dev}"
)
set
.
dev
=
set
.
dev
.
id
}
if
(
set
[
"valve"
]
!=
null
)
{
log
.
debug
(
"valve set: ${set.valve}"
)
set
.
valve
=
set
.
valve
.
id
}
log
.
debug
(
set
)
return
set
}
def
devAction
(
action
)
{
if
(
dev
)
{
log
.
debug
(
"device: ${dev}, action: ${action}"
)
dev
.
"${action}"
()
}
}
def
isValveStatus
(
status
)
{
def
result
=
false
log
.
debug
(
"Water Valve ${valve} has status ${valve.currentState("
contact
").value}, compared to ${status.toLowerCase()}"
)
if
(
valve
)
{
if
(
valve
.
currentState
(
"contact"
).
value
==
status
.
toLowerCase
())
{
result
=
true
}
}
return
result
}
def
initialize
()
{
// TODO: subscribe to attributes, devices, locations, etc.
}
def
uninstalled
()
{
// external cleanup. No need to unsubscribe or remove scheduled jobs
}
// TODO: implement event handlers
\ No newline at end of file
flow meter (fmi)/Consumption Metering/smartapp-consumption-parent.groovy
0 → 100644
View file @
1d4fa8a3
This diff is collapsed.
Click to expand it.
flow meter (fmi)/Leak Detector SmartApp/smartapp-leakdetector-child.groovy
0 → 100644
View file @
1d4fa8a3
/**
* Leak Detector
*
* Copyright 2016 Daniel Kurin
*
*/
definition
(
name:
"Leak Detector"
,
namespace:
"fortrezz"
,
author:
"FortrezZ, LLC"
,
description:
"Child SmartApp for leak detector rules"
,
category:
"Green Living"
,
parent:
"fortrezz:FortrezZ Leak Detector"
,
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
{
page
(
name:
"prefsPage"
,
title:
"Plugin version 1.5\nChoose the detector behavior"
,
install:
true
,
uninstall:
true
)
// Do something here like update a message on the screen,
// or introduce more inputs. submitOnChange will refresh
// the page and allow the user to see the changes immediately.
// For example, you could prompt for the level of the dimmers
// if dimmers have been selected:
//log.debug "Child Settings: ${settings}"
}
def
prefsPage
()
{
def
daysOfTheWeek
=
[
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
]
dynamicPage
(
name:
"prefsPage"
)
{
section
(
"Set Leak Threshold by..."
)
{
input
(
name:
"type"
,
type:
"enum"
,
title:
"Type..."
,
submitOnChange:
true
,
options:
ruleTypes
())
}
if
(
type
)
{
switch
(
type
)
{
case
"Mode"
:
section
(
"Threshold settings"
)
{
input
(
name:
"ruleName"
,
type:
"text"
,
title:
"Rule Name"
,
required:
true
)
input
(
name:
"gpm"
,
type:
"decimal"
,
title:
"GPM exceeds"
,
required:
true
,
defaultValue:
0.1
)
}
section
(
"Only in these modes"
)
{
input
(
name:
"modes"
,
type:
"mode"
,
title:
"select a mode(s)"
,
multiple:
true
,
required:
true
)
}
section
(
"Action"
)
{
input
(
name:
"dev"
,
type:
"capability.actuator"
,
title:
"Choose a device to perform the action"
,
required:
false
,
submitOnChange:
true
)
if
(
dev
)
{
input
(
name:
"command"
,
type:
"enum"
,
title:
"Command..."
,
submitOnChange:
true
,
options:
deviceCommands
(
dev
))
}
}
break
case
"Time Period"
:
section
(
"Threshold settings"
)
{
input
(
name:
"ruleName"
,
type:
"text"
,
title:
"Rule Name"
,
required:
true
)
input
(
name:
"gpm"
,
type:
"decimal"
,
title:
"GPM exceeds"
,
required:
true
)
}
section
(
"Between..."
)
{
input
(
name:
"startTime"
,
type:
"time"
,
title:
"Start Time"
,
required:
true
)
}
section
(
"...and..."
)
{
input
(
name:
"endTime"
,
type:
"time"
,
title:
"End Time"
,
required:
true
)
}
section
(
"Only on these days"
)
{
input
(
name:
"days"
,
type:
"enum"
,
title:
"Days of the week"
,
required:
false
,
options:
daysOfTheWeek
,
multiple:
true
)
}
section
(
"Only in these modes"
)
{
input
(
name:
"modes"
,
type:
"mode"
,
title:
"System Modes"
,
required:
false
,
multiple:
true
)
}
section
(
"Action"
)
{
input
(
name:
"dev"
,
type:
"capability.actuator"
,
title:
"Choose a device to perform the action"
,
required:
false
,
submitOnChange:
true
)
if
(
dev
)
{
input
(
name:
"command"
,
type:
"enum"
,
title:
"Command..."
,
submitOnChange:
true
,
options:
deviceCommands
(
dev
))
}
}
break
case
"Accumulated Flow"
:
section
(
"Threshold settings"
)
{
input
(
name:
"ruleName"
,
type:
"text"
,
title:
"Rule Name"
,
required:
true
)
input
(
name:
"gallons"
,
type:
"number"
,
title:
"Total Gallons exceeds"
,
required:
true
)
}
section
(
"Between..."
)
{
input
(
name:
"startTime"
,
type:
"time"
,
title:
"Start Time"
,
required:
true
)
}
section
(
"...and..."
)
{
input
(
name:
"endTime"
,
type:
"time"
,
title:
"End Time"
,
required:
true
)
}
section
(
"Only on these days"
)
{
input
(
name:
"days"
,
type:
"enum"
,
title:
"Days of the week"
,
required:
false
,
options:
daysOfTheWeek
,
multiple:
true
)
}
section
(
"Only in these modes"
)
{
input
(
name:
"modes"
,
type:
"mode"
,
title:
"System Modes"
,
required:
false
,
multiple:
true
)
}
section
(
"Action"
)
{
input
(
name:
"dev"
,
type:
"capability.actuator"
,
title:
"Choose a device to perform the action"
,
required:
false
,
submitOnChange:
true
)
if
(
dev
)
{
input
(
name:
"command"
,
type:
"enum"
,
title:
"Command..."
,
submitOnChange:
true
,
options:
deviceCommands
(
dev
))
}
}
break
case
"Continuous Flow"
:
section
(
"Threshold settings"
)
{
input
(
name:
"ruleName"
,
type:
"text"
,
title:
"Rule Name"
,
required:
true
)
input
(
name:
"flowMinutes"
,
type:
"number"
,
title:
"Minutes of constant flow"
,
required:
true
,
defaultValue:
60
)
}
section
(
"Only in these modes"
)
{
input
(
name:
"modes"
,
type:
"mode"
,
title:
"System Modes"
,
required:
false
,
multiple:
true
)
}
section
(
"Action"
)
{
input
(
name:
"dev"
,
type:
"capability.actuator"
,
title:
"Choose a device to perform the action"
,
required:
false
,
submitOnChange:
true
)
if
(
dev
)
{
input
(
name:
"command"
,
type:
"enum"
,
title:
"Command..."
,
submitOnChange:
true
,
options:
deviceCommands
(
dev
))
}
}
break
case
"Water Valve Status"
:
section
(
"Threshold settings"
)
{
input
(
name:
"ruleName"
,
type:
"text"
,
title:
"Rule Name"
,
required:
true
)
input
(
name:
"gpm"
,
type:
"decimal"
,
title:
"GPM exceeds"
,
required:
true
,
defaultValue:
0.1
)
}
section
(
"While..."
)
{
input
(
name:
"valve"
,
type:
"capability.valve"
,
title:
"Choose a valve"
,
required:
true
)
}
section
(
"...is..."
)
{
input
(
name:
"valveStatus"
,
type:
"enum"
,
title:
"Status"
,
options:
[
"Open"
,
"Closed"
],
required:
true
)
}
break
case
"Switch Status"
:
section
(
"Threshold settings"
)
{
input
(
name:
"ruleName"
,
type:
"text"
,
title:
"Rule Name"
,
required:
true
)
input
(
name:
"gpm"
,
type:
"decimal"
,
title:
"GPM exceeds"
,
required:
true
,
defaultValue:
0.1
)
}
section
(
"If..."
)
{
input
(
name:
"valve"
,
type:
"capability.switch"
,
title:
"Choose a switch"
,
required:
true
)
}
section
(
"...is..."
)
{
input
(
name:
"switchStatus"
,
type:
"enum"
,
title:
"Status"
,
options:
[
"On"
,
"Off"
],
required:
true
)
}
break
default:
break
}
}
}
}
def
ruleTypes
()
{
def
types
=
[]
types
<<
"Mode"
types
<<
"Time Period"
types
<<
"Accumulated Flow"
types
<<
"Continuous Flow"
types
<<
"Water Valve Status"
//types << "Switch Status"
return
types
}
def
actionTypes
()
{
def
types
=
[]
types
<<
[
name:
"Switch"
,
capability:
"capabilty.switch"
]
types
<<
[
name:
"Water Valve"
,
capability:
"capability.valve"
]
return
types
}
def
deviceCommands
(
dev
)
{
def
cmds
=
[]
dev
.
supportedCommands
.
each
{
command
->
cmds
<<
command
.
name
}
return
cmds
}
def
installed
()
{
log
.
debug
"Installed with settings: ${settings}"
app
.
updateLabel
(
"${ruleName ? ruleName : ""} - ${type}"
)
initialize
()
}
def
updated
()
{
log
.
debug
"Updated with settings: ${settings}"
app
.
updateLabel
(
"${ruleName ? ruleName : ""} - ${type}"
)
unsubscribe
()
initialize
()
}
def
settings
()
{
def
set
=
settings
if
(
set
[
"dev"
]
!=
null
)
{
log
.
debug
(
"dev set: ${set.dev}"
)
set
.
dev
=
set
.
dev
.
id
}
if
(
set
[
"valve"
]
!=
null
)
{
log
.
debug
(
"valve set: ${set.valve}"
)
set
.
valve
=
set
.
valve
.
id
}
log
.
debug
(
set
)
return
set
}
def
devAction
(
action
)
{
if
(
dev
)
{
log
.
debug
(
"device: ${dev}, action: ${action}"
)
dev
.
"${action}"
()
}
}
def
isValveStatus
(
status
)
{
def
result
=
false
log
.
debug
(
"Water Valve ${valve} has status ${valve.currentState("
contact
").value}, compared to ${status.toLowerCase()}"
)
if
(
valve
)
{
if
(
valve
.
currentState
(
"contact"
).
value
==
status
.
toLowerCase
())
{
result
=
true
}
}
return
result
}
def
initialize
()
{
// TODO: subscribe to attributes, devices, locations, etc.
}
// TODO: implement event handlers
\ No newline at end of file
flow meter (fmi)/Leak Detector SmartApp/smartapp-leakdetector-parent.groovy
0 → 100644
View file @
1d4fa8a3
/**
* Leak Detector for FortrezZ Water Meter
*
* Copyright 2016 Daniel Kurin
*
*/
definition
(
name:
"FortrezZ Leak Detector"
,
namespace:
"fortrezz"
,
author:
"FortrezZ, LLC"
,
description:
"Use the FortrezZ Water Meter to identify leaks in your home's water system."
,
category:
"Green Living"
,
iconUrl:
"http://swiftlet.technology/wp-content/uploads/2016/05/logo-square-200-1.png"
,
iconX2Url:
"http://swiftlet.technology/wp-content/uploads/2016/05/logo-square-500.png"
,
iconX3Url:
"http://swiftlet.technology/wp-content/uploads/2016/05/logo-square.png"
)
preferences
{
page
(
name:
"page2"
,
title:
"Plugin version 1.5\nSelect device and actions"
,
install:
true
,
uninstall:
true
)
}
def
page2
()
{
dynamicPage
(
name:
"page2"
)
{
section
(
"Choose a water meter to monitor:"
)
{
input
(
name:
"meter"
,
type:
"capability.energyMeter"
,
title:
"Water Meter"
,
description:
null
,
required:
true
,
submitOnChange:
true
)
}
if
(
meter
)
{
section
{
app
(
name:
"childRules"
,
appName:
"Leak Detector"
,
namespace:
"fortrezz"
,
title:
"Create New Leak Detector..."
,
multiple:
true
)
}
}
section
(
"Send notifications through..."
)
{
input
(
name:
"pushNotification"
,
type:
"bool"
,
title:
"SmartThings App"
,
required:
false
)
input
(
name:
"smsNotification"
,
type:
"bool"
,
title:
"Text Message (SMS)"
,
submitOnChange:
true
,
required:
false
)
if
(
smsNotification
)
{
input
(
name:
"phone"
,
type:
"phone"
,
title:
"Phone number?"
,
required:
true
)
}
input
(
name:
"minutesBetweenNotifications"
,
type:
"number"
,
title:
"Minutes between notifications"
,
required:
true
,
defaultValue:
60
)
}
log
.
debug
"there are ${childApps.size()} child smartapps"
def
childRules
=
[]
childApps
.
each
{
child
->
//log.debug "child ${child.id}: ${child.settings()}"
childRules
<<
[
id:
child
.
id
,
rules:
child
.
settings
()]
}
state
.
rules
=
childRules
//log.debug("Child Rules: ${state.rules} w/ length ${state.rules.toString().length()}")
log
.
debug
"Parent Settings: ${settings}"
}
}
def
installed
()
{
log
.
debug
"Installed with settings: ${settings}"
initialize
()
}
def
updated
()
{
log
.
debug
"Updated with settings: ${settings}"
unsubscribe
()
initialize
()
}
def
initialize
()
{
subscribe
(
meter
,
"cumulative"
,
cumulativeHandler
)
subscribe
(
meter
,
"gpm"
,
gpmHandler
)
log
.
debug
(
"Subscribing to events"
)
}
def
cumulativeHandler
(
evt
)
{
//Date Stuff
def
daysOfTheWeek
=
[
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
]
def
today
=
new
Date
()
today
.
clearTime
()
Calendar
c
=
Calendar
.
getInstance
();
c
.
setTime
(
today
);
int
dow
=
c
.
get
(
Calendar
.
DAY_OF_WEEK
);
def
dowName
=
daysOfTheWeek
[
dow
-
1
]
def
gpm
=
meter
.
latestValue
(
"gpm"
)
def
cumulative
=
new
BigDecimal
(
evt
.
value
)
log
.
debug
"Cumulative Handler: [gpm: ${gpm}, cumulative: ${cumulative}]"
def
rules
=
state
.
rules
rules
.
each
{
it
->
def
r
=
it
.
rules
def
childAppID
=
it
.
id
//log.debug("Rule: ${r}")
switch
(
r
.
type
)
{
case
"Mode"
:
log
.
debug
(
"Mode Test: ${location.currentMode} in ${r.modes}... ${findIn(r.modes, location.currentMode)}"
)
if
(
findIn
(
r
.
modes
,
location
.
currentMode
))
{
log
.
debug
(
"Threshold:${r.gpm}, Value:${gpm}"
)
if
(
gpm
>
r
.
gpm
)
{
sendNotification
(
childAppID
,
gpm
)
if
(
r
.
dev
)
{
//log.debug("Child App: ${childAppID}")
def
activityApp
=
getChildById
(
childAppID
)
activityApp
.
devAction
(
r
.
command
)
}
}
}
break
case
"Time Period"
:
log
.
debug
(
"Time Period Test: ${r}"
)
def
boolTime
=
timeOfDayIsBetween
(
r
.
startTime
,
r
.
endTime
,
new
Date
(),
location
.
timeZone
)
def
boolDay
=
!
r
.
days
||
findIn
(
r
.
days
,
dowName
)
// Truth Table of this mess: http://swiftlet.technology/wp-content/uploads/2016/05/IMG_20160523_150600.jpg
def
boolMode
=
!
r
.
modes
||
findIn
(
r
.
modes
,
location
.
currentMode
)