mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-14 05:11:50 +00:00
Compare commits
1 Commits
MSA-2099-1
...
MSA-2101-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f1108e1a0 |
@@ -0,0 +1,284 @@
|
||||
/**
|
||||
* SmartThings Device Handler: Yamaha Zone
|
||||
*
|
||||
* Author: redloro@gmail.com
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "Yamaha Zone", namespace: "redloro-smartthings", author: "redloro@gmail.com") {
|
||||
|
||||
/**
|
||||
* List our capabilties. Doing so adds predefined command(s) which
|
||||
* belong to the capability.
|
||||
*/
|
||||
capability "Music Player"
|
||||
capability "Switch"
|
||||
capability "Switch Level"
|
||||
capability "Refresh"
|
||||
capability "Polling"
|
||||
capability "Sensor"
|
||||
capability "Actuator"
|
||||
|
||||
/**
|
||||
* Define all commands, ie, if you have a custom action not
|
||||
* covered by a capability, you NEED to define it here or
|
||||
* the call will not be made.
|
||||
*
|
||||
* To call a capability function, just prefix it with the name
|
||||
* of the capability, for example, refresh would be "refresh.refresh"
|
||||
*/
|
||||
command "source0"
|
||||
command "source1"
|
||||
command "source2"
|
||||
command "source3"
|
||||
command "source4"
|
||||
command "source5"
|
||||
command "mutedOn"
|
||||
command "mutedOff"
|
||||
command "partyModeOn"
|
||||
command "partyModeOff"
|
||||
command "zone"
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the various tiles and the states that they can be in.
|
||||
* The 2nd parameter defines an event which the tile listens to,
|
||||
* if received, it tries to map it to a state.
|
||||
*
|
||||
* You can also use ${currentValue} for the value of the event
|
||||
* or ${name} for the name of the event. Just make SURE to use
|
||||
* single quotes, otherwise it will only be interpreted at time of
|
||||
* launch, instead of every time the event triggers.
|
||||
*/
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"state", type:"lighting", width:6, height:4) {
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'On', action:"switch.off", icon:"st.Electronics.electronics16", backgroundColor:"#79b821", nextState:"off"
|
||||
attributeState "off", label:'Off', action:"switch.on", icon:"st.Electronics.electronics16", backgroundColor:"#ffffff", nextState:"on"
|
||||
}
|
||||
tileAttribute ("source", key: "SECONDARY_CONTROL") {
|
||||
attributeState "source", label:'${currentValue}'
|
||||
}
|
||||
}
|
||||
|
||||
// row
|
||||
//controlTile("volume", "device.volume", "slider", height: 1, width: 6, range:"(0..100)") {
|
||||
controlTile("volume", "device.volume", "slider", height: 1, width: 6, range:"(-80..16)") {
|
||||
state "volume", label: "Volume", action:"music Player.setLevel", backgroundColor:"#00a0dc"
|
||||
}
|
||||
|
||||
// row
|
||||
standardTile("0", "device.source0", decoration: "flat", width: 2, height: 2) {
|
||||
state("off", label:"AV1", action:"source0", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff")
|
||||
state("on", label:"AV1", action:"source0", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-green.png", backgroundColor:"#ffffff")
|
||||
}
|
||||
standardTile("1", "device.source1", decoration: "flat", width: 2, height: 2) {
|
||||
state("off", label:"AV2", action:"source1", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff")
|
||||
state("on", label:"AV2", action:"source1", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-green.png", backgroundColor:"#ffffff")
|
||||
}
|
||||
standardTile("2", "device.source2", decoration: "flat", width: 2, height: 2) {
|
||||
state("off", label:"AV3", action:"source2", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff")
|
||||
state("on", label:"AV3", action:"source2", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-green.png", backgroundColor:"#ffffff")
|
||||
}
|
||||
standardTile("3", "device.source3", decoration: "flat", width: 2, height: 2) {
|
||||
state("off", label:"AV4", action:"source3", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff")
|
||||
state("on", label:"AV4", action:"source3", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-green.png", backgroundColor:"#ffffff")
|
||||
}
|
||||
standardTile("4", "device.source4", decoration: "flat", width: 2, height: 2) {
|
||||
state("off", label:"AV5", action:"source4", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff")
|
||||
state("on", label:"AV5", action:"source4", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-green.png", backgroundColor:"#ffffff")
|
||||
}
|
||||
standardTile("5", "device.source5", decoration: "flat", width: 2, height: 2) {
|
||||
state("off", label:"AV6", action:"source5", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff")
|
||||
state("on", label:"AV6", action:"source5", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-green.png", backgroundColor:"#ffffff")
|
||||
}
|
||||
|
||||
// row
|
||||
standardTile("muted", "device.muted", decoration: "flat", width: 2, height: 2) {
|
||||
state("off", label:'Muted', action:"mutedOn", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff", nextState:"on")
|
||||
state("on", label:'Muted', action:"mutedOff", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-mute.png", backgroundColor:"#ffffff", nextState:"off")
|
||||
}
|
||||
standardTile("partyMode", "device.partyMode", decoration: "flat", width: 2, height: 2, inactiveLabel: false) {
|
||||
state("off", label:'Party Mode', action:"partyModeOn", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-gray.png", backgroundColor:"#ffffff", nextState:"on")
|
||||
state("on", label:'Party Mode', action:"partyModeOff", icon:"https://raw.githubusercontent.com/redloro/smartthings/master/images/indicator-dot-party.png", backgroundColor:"#ffffff", nextState:"off")
|
||||
}
|
||||
standardTile("refresh", "device.status", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:"Refresh", action:"refresh.refresh", icon:"st.secondary.refresh-icon", backgroundColor:"#ffffff"
|
||||
}
|
||||
|
||||
// Defines which tile to show in the overview
|
||||
main "state"
|
||||
|
||||
// Defines which tile(s) to show when user opens the detailed view
|
||||
details([
|
||||
"state",
|
||||
"volume",
|
||||
"0","1","2","3","4","5",
|
||||
"muted", "partyMode","refresh"
|
||||
])
|
||||
}
|
||||
|
||||
preferences {
|
||||
input name: "source0", type: "text", title: "Source 1", defaultValue: "AV1"
|
||||
input name: "source1", type: "text", title: "Source 2", defaultValue: "AV2"
|
||||
input name: "source2", type: "text", title: "Source 3", defaultValue: "AV3"
|
||||
input name: "source3", type: "text", title: "Source 4", defaultValue: "AV4"
|
||||
input name: "source4", type: "text", title: "Source 5", defaultValue: "AV5"
|
||||
input name: "source5", type: "text", title: "Source 6", defaultValue: "AV6"
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* The following section simply maps the actions as defined in
|
||||
* the metadata into onAction() calls.
|
||||
*
|
||||
* This is preferred since some actions can be dealt with more
|
||||
* efficiently this way. Also keeps all user interaction code in
|
||||
* one place.
|
||||
*
|
||||
*/
|
||||
def on() {
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><${getZone()}><Power_Control><Power>On</Power></Power_Control></${getZone()}></YAMAHA_AV>")
|
||||
sendEvent(name: "switch", value: "on")
|
||||
}
|
||||
def off() {
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><${getZone()}><Power_Control><Power>Standby</Power></Power_Control></${getZone()}></YAMAHA_AV>")
|
||||
sendEvent(name: "switch", value: "off")
|
||||
}
|
||||
def setLevel(value) {
|
||||
//sendCommand("<YAMAHA_AV cmd=\"PUT\"><${getZone()}><Volume><Lvl><Val>${(Math.round(value * 9 / 5) * 5 - 800).intValue()}</Val><Exp>1</Exp><Unit>dB</Unit></Lvl></Volume></${getZone()}></YAMAHA_AV>")
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><${getZone()}><Volume><Lvl><Val>${(value * 10).intValue()}</Val><Exp>1</Exp><Unit>dB</Unit></Lvl></Volume></${getZone()}></YAMAHA_AV>")
|
||||
sendEvent(name: "volume", value: value)
|
||||
}
|
||||
def source0() {
|
||||
setSource(0)
|
||||
}
|
||||
def source1() {
|
||||
setSource(1)
|
||||
}
|
||||
def source2() {
|
||||
setSource(2)
|
||||
}
|
||||
def source3() {
|
||||
setSource(3)
|
||||
}
|
||||
def source4() {
|
||||
setSource(4)
|
||||
}
|
||||
def source5() {
|
||||
setSource(5)
|
||||
}
|
||||
def mutedOn() {
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><${getZone()}><Volume><Mute>On</Mute></Volume></${getZone()}></YAMAHA_AV>")
|
||||
sendEvent(name: "muted", value: "on")
|
||||
}
|
||||
def mutedOff() {
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><${getZone()}><Volume><Mute>Off</Mute></Volume></${getZone()}></YAMAHA_AV>")
|
||||
sendEvent(name: "muted", value: "off")
|
||||
}
|
||||
def partyModeOn() {
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><System><Party_Mode><Mode>On</Mode></Party_Mode></System></YAMAHA_AV>")
|
||||
sendEvent(name: "partyMode", value: "on")
|
||||
}
|
||||
def partyModeOff() {
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><System><Party_Mode><Mode>Off</Mode></Party_Mode></System></YAMAHA_AV>")
|
||||
sendEvent(name: "partyMode", value: "off")
|
||||
}
|
||||
def refresh() {
|
||||
sendCommand("<YAMAHA_AV cmd=\"GET\"><${getZone()}><Basic_Status>GetParam</Basic_Status></${getZone()}></YAMAHA_AV>")
|
||||
sendCommand("<YAMAHA_AV cmd=\"GET\"><System><Party_Mode><Mode>GetParam</Mode></Party_Mode></System></YAMAHA_AV>")
|
||||
}
|
||||
/**************************************************************************/
|
||||
|
||||
/**
|
||||
* Called every so often (every 5 minutes actually) to refresh the
|
||||
* tiles so the user gets the correct information.
|
||||
*/
|
||||
def poll() {
|
||||
refresh()
|
||||
}
|
||||
|
||||
def parse(String description) {
|
||||
return
|
||||
}
|
||||
|
||||
def setSource(id) {
|
||||
//log.debug "source: "+getSourceName(id)
|
||||
sendCommand("<YAMAHA_AV cmd=\"PUT\"><${getZone()}><Input><Input_Sel>"+getSourceName(id)+"</Input_Sel></Input></${getZone()}></YAMAHA_AV>")
|
||||
setSourceTile(getSourceName(id))
|
||||
}
|
||||
|
||||
def getSourceName(id) {
|
||||
if (settings) {
|
||||
return settings."source${id}"
|
||||
} else {
|
||||
return ['AV1', 'AV2', 'AV3', 'AV4', 'AV5', 'AV6'].get(id)
|
||||
}
|
||||
}
|
||||
|
||||
def setSourceTile(name) {
|
||||
sendEvent(name: "source", value: "Source: ${name}")
|
||||
for (def i = 0; i < 6; i++) {
|
||||
if (name == getSourceName(i)) {
|
||||
sendEvent(name: "source${i}", value: "on")
|
||||
}
|
||||
else {
|
||||
sendEvent(name: "source${i}", value: "off")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def zone(evt) {
|
||||
/*
|
||||
* Zone On/Off
|
||||
*/
|
||||
if (evt.Basic_Status.Power_Control.Power.text()) {
|
||||
sendEvent(name: "switch", value: (evt.Basic_Status.Power_Control.Power.text() == "On") ? "on" : "off")
|
||||
}
|
||||
|
||||
/*
|
||||
* Zone Volume
|
||||
*/
|
||||
if (evt.Basic_Status.Volume.Lvl.Val.text()) {
|
||||
def int volLevel = evt.Basic_Status.Volume.Lvl.Val.toInteger() ?: -250
|
||||
//sendEvent(name: "volume", value: ((volLevel + 800) / 9).intValue())
|
||||
sendEvent(name: "volume", value: (volLevel / 10).intValue())
|
||||
}
|
||||
|
||||
/*
|
||||
* Zone Muted
|
||||
*/
|
||||
if (evt.Basic_Status.Volume.Mute.text()) {
|
||||
sendEvent(name: "muted", value: (evt.Basic_Status.Volume.Mute.text() == "On") ? "on" : "off")
|
||||
}
|
||||
|
||||
/*
|
||||
* Zone Source
|
||||
*/
|
||||
if (evt.Basic_Status.Input.Input_Sel.text()) {
|
||||
setSourceTile(evt.Basic_Status.Input.Input_Sel.text())
|
||||
}
|
||||
|
||||
/*
|
||||
* Party Mode
|
||||
*/
|
||||
if (evt.Party_Mode.Mode.text()) {
|
||||
sendEvent(name: "partyMode", value: (evt.Party_Mode.Mode.text() == "On") ? "on" : "off")
|
||||
}
|
||||
}
|
||||
|
||||
private sendCommand(body) {
|
||||
parent.sendCommand(body)
|
||||
}
|
||||
|
||||
private getZone() {
|
||||
return new String(device.deviceNetworkId).tokenize('|')[2]
|
||||
}
|
||||
@@ -1,470 +0,0 @@
|
||||
/* **DISCLAIMER**
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* Without limitation of the foregoing, Contributors/Regents expressly does not warrant that:
|
||||
* 1. the software will meet your requirements or expectations;
|
||||
* 2. the software or the software content will be free of bugs, errors, viruses or other defects;
|
||||
* 3. any results, output, or data provided through or generated by the software will be accurate, up-to-date, complete or reliable;
|
||||
* 4. the software will be compatible with third party software;
|
||||
* 5. any errors in the software will be corrected.
|
||||
* The user assumes all responsibility for selecting the software and for the results obtained from the use of the software. The user shall bear the entire risk as to the quality and the performance of the software.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 5-2 Day Thermostat
|
||||
*
|
||||
* Base code from mwoodengr@hotmail.com, bugfixed and enhanced by RBoy
|
||||
* Changes Copyright RBoy, redistribution of any changes or modified code is not allowed without permission
|
||||
* Version 2.1.0
|
||||
* 2015-10-3 - Fixed an issue with selecting multiple thermostats and for recent platform changes
|
||||
* 2015-5-17 - Added ability to select mutiple thermostats simultaneously
|
||||
* 2015-2-11 - Fixed issue with fan mode
|
||||
*
|
||||
*/
|
||||
definition(
|
||||
name: "5-2 Day Thermostat",
|
||||
namespace: "rboy",
|
||||
author: "RBoy",
|
||||
description: "Weekday and Weekend Thermostat",
|
||||
category: "Green Living",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/GreenLiving/Cat-GreenLiving.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/GreenLiving/Cat-GreenLiving@2x.png",
|
||||
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/GreenLiving/Cat-GreenLiving@3x.png")
|
||||
|
||||
preferences {
|
||||
section("Choose thermostat (s)") {
|
||||
input "thermostats", "capability.thermostat", required: true, multiple:true
|
||||
}
|
||||
|
||||
section("Switch HVAC mode (auto to cool/heat) based on the outside temperature (optional)") {
|
||||
input "temperatureSensor", "capability.temperatureMeasurement", required: false
|
||||
input "temperatureH", "number", title: "Switch to heating temperature", required: false, description: "Temperature below which switch to heat mode"
|
||||
input "temperatureC", "number", title: "Switch to cooling temperature", required: false, description: "Temperature above which switch to cool mode"
|
||||
}
|
||||
|
||||
section("Monday to Friday Schedule") {
|
||||
input "time1", "time", title: "Wake Time", required: true
|
||||
input "tempSetpoint1", "number", title: "Wake Heat Temp", required: true
|
||||
input "tempSetpointA", "number", title: "Wake Cool Temp", required: true
|
||||
input "time2", "time", title: "Leave Time", required: true
|
||||
input "tempSetpoint2", "number", title: "Leave Heat Temp", required: true
|
||||
input "tempSetpointB", "number", title: "Leave Cool Temp", required: true
|
||||
input "time3", "time", title: "Return Time", required: true
|
||||
input "tempSetpoint3", "number", title: "Return Heat Temp", required: true
|
||||
input "tempSetpointC", "number", title: "Return Cool Temp", required: true
|
||||
input "time4", "time", title: "Sleep Time", required: true
|
||||
input "tempSetpoint4", "number", title: "Sleep Heat Temp", required: true
|
||||
input "tempSetpointD", "number", title: "Sleep Cool Temp", required: true
|
||||
}
|
||||
section("Saturday and Sunday Schedule") {
|
||||
input "time11", "time", title: "Wake Time", required: true
|
||||
input "tempSetpoint11", "number", title: "Wake Heat Temp", required: true
|
||||
input "tempSetpointAA", "number", title: "Wake Cool Temp", required: true
|
||||
input "time21", "time", title: "Leave Time", required: true
|
||||
input "tempSetpoint21", "number", title: "Leave Heat Temp", required: true
|
||||
input "tempSetpointBB", "number", title: "Leave Cool Temp", required: true
|
||||
input "time31", "time", title: "Return Time", required: true
|
||||
input "tempSetpoint31", "number", title: "Return Heat Temp", required: true
|
||||
input "tempSetpointCC", "number", title: "Return Cool Temp", required: true
|
||||
input "time41", "time", title: "Sleep Time", required: true
|
||||
input "tempSetpoint41", "number", title: "Sleep Heat Temp", required: true
|
||||
input "tempSetpointDD", "number", title: "Sleep Cool Temp", required: true
|
||||
}
|
||||
}
|
||||
|
||||
def installed()
|
||||
{
|
||||
subscribeToEvents()
|
||||
}
|
||||
|
||||
def updated()
|
||||
{
|
||||
unsubscribe()
|
||||
subscribeToEvents()
|
||||
}
|
||||
|
||||
def subscribeToEvents() {
|
||||
subscribe(temperatureSensor, "temperature", temperatureHandler)
|
||||
subscribe(location, modeChangeHandler)
|
||||
|
||||
initialize()
|
||||
}
|
||||
|
||||
// Handle mode changes, reinitialize the current temperature and timers after a mode change, this is to workaround the issue of the last timer firing while in a non running mode, resume operations when supported modes are set
|
||||
def modeChangeHandler(evt) {
|
||||
log.debug "Reinitializing thermostats on mode change notification, new mode $evt.value"
|
||||
//sendNotificationEvent("$thermostats Reinitializing on mode change notification, new mode $evt.value")
|
||||
initialize()
|
||||
}
|
||||
|
||||
// This section sets the HVAC mode based outside temperature. HVAC fan mode is set to "auto".
|
||||
def temperatureHandler(evt) {
|
||||
log.debug "Heat mode switch temperature $temperatureH, cool mode switch temperature $temperatureC"
|
||||
|
||||
if (temperatureH == null || temperatureC == null) { // We are in Auto mode or user doesn't want us to switch modes
|
||||
return
|
||||
}
|
||||
|
||||
thermostats.each { thermostat ->
|
||||
def extTemp = temperatureSensor.currentTemperature
|
||||
log.debug "External temperature is: $extTemp"
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "HVAC current mode $thermostatState"
|
||||
log.debug "HVAC Fan current mode $thermostatFan"
|
||||
if (extTemp < temperatureH) {
|
||||
if (thermostatState == "cool") {
|
||||
def hvacmode = "heat"
|
||||
thermostat.setThermostatMode(hvacmode)
|
||||
log.debug "HVAC mode set to $hvacmode"
|
||||
}
|
||||
}
|
||||
else if (extTemp > temperatureC) {
|
||||
if (thermostatState == "heat") {
|
||||
def hvacmode = "cool"
|
||||
thermostat.setThermostatMode(hvacmode)
|
||||
log.debug "HVAC mode set to $hvacmode"
|
||||
}
|
||||
}
|
||||
|
||||
if (thermostatFan != "fanAuto") {
|
||||
thermostat.setThermostatFanMode("auto")
|
||||
log.debug "HVAC fan mode set to auto"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This section determines which day it is.
|
||||
def initialize() {
|
||||
log.trace "Initialized with $settings"
|
||||
|
||||
unschedule()
|
||||
def calendar = Calendar.getInstance()
|
||||
calendar.setTimeZone(location.timeZone)
|
||||
def today = calendar.get(Calendar.DAY_OF_WEEK)
|
||||
def timeNow = now()
|
||||
def midnightToday = timeToday("2000-01-01T23:59:59.999-0000", location.timeZone)
|
||||
log.debug("Current time is ${(new Date(timeNow)).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
log.debug("Midnight today is ${midnightToday.format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekday schedule1 ${timeToday(time1, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekday schedule2 ${timeToday(time2, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekday schedule3 ${timeToday(time3, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekday schedule4 ${timeToday(time4, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekend schedule1 ${timeToday(time11, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekend schedule2 ${timeToday(time21, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekend schedule3 ${timeToday(time31, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
log.trace("Weekend schedule4 ${timeToday(time41, location.timeZone).format("HH:mm z", location.timeZone)}")
|
||||
|
||||
// This section is where the time/temperature schedule is set
|
||||
switch (today) {
|
||||
case Calendar.MONDAY:
|
||||
case Calendar.TUESDAY:
|
||||
case Calendar.WEDNESDAY:
|
||||
case Calendar.THURSDAY:
|
||||
if (timeNow >= timeToday(time1, location.timeZone).time && timeNow < timeToday(time2, location.timeZone).time) { // Are we between 1st time and 2nd time
|
||||
changeTemp1()
|
||||
schedule(timeToday(time2, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time2, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time2, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time2, location.timeZone).time && timeNow < timeToday(time3, location.timeZone).time) { // Are we between 2nd time and 3rd time
|
||||
changeTemp2()
|
||||
schedule(timeToday(time3, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time3, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time3, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time3, location.timeZone).time && timeNow < timeToday(time4, location.timeZone).time) { // Are we between 3rd time and 4th time
|
||||
changeTemp3()
|
||||
schedule(timeToday(time4, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time4, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time4, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time4, location.timeZone).time && timeNow < midnightToday.time) { // Are we between 4th time and midnight, schedule next day
|
||||
changeTemp4()
|
||||
schedule(timeToday(time1, location.timeZone) + 1, initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${(timeToday(time1, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${(timeToday(time1, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= (midnightToday - 1).time && timeNow < timeToday(time1, location.timeZone).time) { // Are we between midnight yesterday and 1st time, schedule today
|
||||
changeTemp4()
|
||||
schedule(timeToday(time1, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time1, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time1, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
break
|
||||
|
||||
case Calendar.FRIDAY:
|
||||
if (timeNow >= timeToday(time1, location.timeZone).time && timeNow < timeToday(time2, location.timeZone).time) { // Are we between 1st time and 2nd time
|
||||
changeTemp1()
|
||||
schedule(timeToday(time2, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time2, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time2, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time2, location.timeZone).time && timeNow < timeToday(time3, location.timeZone).time) { // Are we between 2nd time and 3rd time
|
||||
changeTemp2()
|
||||
schedule(timeToday(time3, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time3, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time3, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time3, location.timeZone).time && timeNow < timeToday(time4, location.timeZone).time) { // Are we between 3rd time and 4th time
|
||||
changeTemp3()
|
||||
schedule(timeToday(time4, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time4, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time4, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time4, location.timeZone).time && timeNow < midnightToday.time) { // Are we between 4th time Friday and midnight, we schedule Saturday
|
||||
changeTemp4()
|
||||
schedule(timeToday(time11, location.timeZone) + 1, initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${(timeToday(time11, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${(timeToday(time11, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= (midnightToday - 1).time && timeNow < timeToday(time11, location.timeZone).time) { // Are we between midnight Friday and 1st time on Saturday, we schedule Saturday
|
||||
changeTemp4()
|
||||
schedule(timeToday(time11, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time11, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time11, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
break
|
||||
|
||||
case Calendar.SATURDAY:
|
||||
if (timeNow >= timeToday(time11, location.timeZone).time && timeNow < timeToday(time21, location.timeZone).time) { // Are we between 1st time and 2nd time
|
||||
changeTemp11()
|
||||
schedule(timeToday(time21, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time21, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time21, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time21, location.timeZone).time && timeNow < timeToday(time31, location.timeZone).time) { // Are we between 2nd time and 3rd time
|
||||
changeTemp21()
|
||||
schedule(timeToday(time31, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time31, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time31, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time31, location.timeZone).time && timeNow < timeToday(time41, location.timeZone).time) { // Are we between 3rd time and 4th time
|
||||
changeTemp31()
|
||||
schedule(timeToday(time41, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time41, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time41, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time41, location.timeZone).time && timeNow < midnightToday.time) { // Are we between 4th time and midnight, schedule the next day
|
||||
changeTemp41()
|
||||
schedule(timeToday(time11, location.timeZone) + 1, initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${(timeToday(time11, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${(timeToday(time11, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= (midnightToday - 1).time && timeNow < timeToday(time11, location.timeZone).time) { // Are we between midnight yesterday and 1st time, schedule today
|
||||
changeTemp41()
|
||||
schedule(timeToday(time11, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time11, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time11, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
break
|
||||
|
||||
case Calendar.SUNDAY:
|
||||
if (timeNow >= timeToday(time11, location.timeZone).time && timeNow < timeToday(time21, location.timeZone).time) { // Are we between 1st time and 2nd time
|
||||
changeTemp11()
|
||||
schedule(timeToday(time21, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time21, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time21, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time21, location.timeZone).time && timeNow < timeToday(time31, location.timeZone).time) { // Are we between 2nd time and 3rd time
|
||||
changeTemp21()
|
||||
schedule(timeToday(time31, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time31, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time31, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time31, location.timeZone).time && timeNow < timeToday(time41, location.timeZone).time) { // Are we between 3rd time and 4th time
|
||||
changeTemp31()
|
||||
schedule(timeToday(time41, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time41, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time41, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= timeToday(time41, location.timeZone).time && timeNow < midnightToday.time) { // Are we between 4th time Sunday and midnight, we schedule Monday
|
||||
changeTemp41()
|
||||
schedule(timeToday(time1, location.timeZone) + 1, initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${(timeToday(time1, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${(timeToday(time1, location.timeZone) + 1).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
else if (timeNow >= (midnightToday - 1).time && timeNow < timeToday(time1, location.timeZone).time) { // Are we between midnight Sunday and 1st time on Monday, we schedule Monday
|
||||
changeTemp41()
|
||||
schedule(timeToday(time1, location.timeZone), initialize)
|
||||
log.info("$thermostats Scheduled next adjustment for ${timeToday(time1, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
//sendNotificationEvent("$thermostats Scheduled next adjustment for ${timeToday(time1, location.timeZone).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// This section is where the thermostat temperature settings are set.
|
||||
def changeTemp1() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint1)
|
||||
thermostat.setCoolingSetpoint(tempSetpointA)
|
||||
log.info "Set $thermostat Heat $tempSetpoint1°, Cool $tempSetpointA°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint1)
|
||||
log.info "Set $thermostat Heat $tempSetpoint1°"
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointA)
|
||||
log.info "Set $thermostat Cool $tempSetpointA°"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def changeTemp2() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint2)
|
||||
thermostat.setCoolingSetpoint(tempSetpointB)
|
||||
log.info "Set $thermostat Heat $tempSetpoint2°, Cool $tempSetpointB°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint2)
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointB)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def changeTemp3() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint3)
|
||||
thermostat.setCoolingSetpoint(tempSetpointC)
|
||||
log.info "Set $thermostat Heat $tempSetpoint3°, Cool $tempSetpointC°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint3)
|
||||
log.info "Set $thermostat Heat $tempSetpoint3°"
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointC)
|
||||
log.info "Set $thermostat Cool $tempSetpointC°"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def changeTemp4() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint4)
|
||||
thermostat.setCoolingSetpoint(tempSetpointD)
|
||||
log.info "Set $thermostat Heat $tempSetpoint4°, Cool $tempSetpointD°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint4)
|
||||
log.info "Set $thermostat Heat $tempSetpoint4°"
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointD)
|
||||
log.info "Set $thermostat Cool $tempSetpointD°"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def changeTemp11() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint11)
|
||||
thermostat.setCoolingSetpoint(tempSetpointAA)
|
||||
log.info "Set $thermostat Heat $tempSetpoint11°, Cool $tempSetpointAA°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint11)
|
||||
log.info "Set $thermostat Heat $tempSetpoint11°"
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointAA)
|
||||
log.info "Set $thermostat Cool $tempSetpointAA°"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def changeTemp21() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint21)
|
||||
thermostat.setCoolingSetpoint(tempSetpointBB)
|
||||
log.info "Set $thermostat Heat $tempSetpoint21°, Cool $tempSetpointBB°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint21)
|
||||
log.info "Set $thermostat Heat $tempSetpoint21°"
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointBB)
|
||||
log.info "Set $thermostat Cool $tempSetpointBB°"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def changeTemp31() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint31)
|
||||
thermostat.setCoolingSetpoint(tempSetpointCC)
|
||||
log.info "Set $thermostat Heat $tempSetpoint31°, Cool $tempSetpointCC°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint31)
|
||||
log.info "Set $thermostat Heat $tempSetpoint31°"
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointCC)
|
||||
log.info "Set $thermostat Cool $tempSetpointCC°"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def changeTemp41() {
|
||||
thermostats.each { thermostat ->
|
||||
def thermostatState = thermostat.currentThermostatMode
|
||||
log.debug "Thermostat mode = $thermostatState"
|
||||
def thermostatFan = thermostat.currentThermostatFanMode
|
||||
log.debug "Thermostat fan = $thermostatFan"
|
||||
if (thermostatState == "auto") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint41)
|
||||
thermostat.setCoolingSetpoint(tempSetpointDD)
|
||||
log.info "Set $thermostat Heat $tempSetpoint41°, Cool $tempSetpointDD°"
|
||||
}
|
||||
else if (thermostatState == "heat") {
|
||||
thermostat.setHeatingSetpoint(tempSetpoint41)
|
||||
log.info "Set $thermostat Heat $tempSetpoint41°"
|
||||
}
|
||||
else {
|
||||
thermostat.setCoolingSetpoint(tempSetpointDD)
|
||||
log.info "Set $thermostat Cool $tempSetpointDD°"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* SmartThings SmartApp: Yamaha Network Receiver
|
||||
*
|
||||
* Author: redloro@gmail.com
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* https://github.com/PSeitz/yamaha-nodejs
|
||||
* http://<RECEIVER_IP_ADDRESS>/YamahaRemoteControl/desc.xml
|
||||
*/
|
||||
import groovy.util.XmlSlurper
|
||||
|
||||
definition(
|
||||
name: "Yamaha Receiver",
|
||||
namespace: "redloro-smartthings",
|
||||
author: "redloro@gmail.com",
|
||||
description: "Yamaha SmartApp",
|
||||
category: "My Apps",
|
||||
iconUrl: "https://raw.githubusercontent.com/redloro/smartthings/master/images/yamaha-receiver.png",
|
||||
iconX2Url: "https://raw.githubusercontent.com/redloro/smartthings/master/images/yamaha-receiver.png",
|
||||
iconX3Url: "https://raw.githubusercontent.com/redloro/smartthings/master/images/yamaha-receiver.png"
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("SmartThings Hub") {
|
||||
input "hostHub", "hub", title: "Select Hub", multiple: false, required: true
|
||||
}
|
||||
section("Yamaha Receiver") {
|
||||
input name: "receiverName", type: "text", title: "Name", required: true, defaultValue: "Yamaha"
|
||||
input name: "receiverIp", type: "text", title: "IP", required: true
|
||||
input name: "receiverZones", type: "enum", title: "Zones", required: true, multiple: true, options: ["Main_Zone","Zone_B","Zone_2","Zone_3","Zone_4"]
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
subscribeToEvents()
|
||||
}
|
||||
|
||||
def subscribeToEvents() {
|
||||
subscribe(location, null, lanResponseHandler, [filterEvents:false])
|
||||
}
|
||||
|
||||
def updated() {
|
||||
addChildDevices()
|
||||
}
|
||||
|
||||
def uninstalled() {
|
||||
removeChildDevices()
|
||||
}
|
||||
|
||||
def lanResponseHandler(evt) {
|
||||
def map = stringToMap(evt.stringValue)
|
||||
|
||||
//verify that this message is from Yamaha Receiver IP
|
||||
if (!map.ip || map.ip != convertIPtoHex(settings.receiverIp)) {
|
||||
return
|
||||
}
|
||||
|
||||
def headers = getHttpHeaders(map.headers);
|
||||
def body = getHttpBody(map.body);
|
||||
//log.trace "Headers: ${headers}"
|
||||
//log.trace "Body: ${body}"
|
||||
|
||||
updateZoneDevices(body.children()[0])
|
||||
}
|
||||
|
||||
private updateZoneDevices(evt) {
|
||||
//log.debug "updateZoneDevices: ${evt.toString()}"
|
||||
if (evt.name() == "System") {
|
||||
//log.debug "Update all zones"
|
||||
childDevices*.zone(evt)
|
||||
return
|
||||
}
|
||||
|
||||
def zonedevice = getChildDevice(getDeviceId(evt.name()))
|
||||
if (zonedevice) {
|
||||
zonedevice.zone(evt)
|
||||
}
|
||||
|
||||
//check for Zone_B
|
||||
zonedevice = getChildDevice(getDeviceId("Zone_B"))
|
||||
if (zonedevice && evt.name() == "Main_Zone") {
|
||||
zonedevice.zone(evt)
|
||||
}
|
||||
}
|
||||
|
||||
private addChildDevices() {
|
||||
// add yamaha device
|
||||
settings.receiverZones.each {
|
||||
def deviceId = getDeviceId(it)
|
||||
if (!getChildDevice(deviceId)) {
|
||||
addChildDevice("redloro-smartthings", "Yamaha Zone", deviceId, hostHub.id, ["name": it, label: "${settings.receiverName}: ${it}", completedSetup: true])
|
||||
log.debug "Added Yamaha zone: ${deviceId}"
|
||||
}
|
||||
}
|
||||
|
||||
childDevices*.refresh()
|
||||
}
|
||||
|
||||
private removeChildDevices() {
|
||||
getAllChildDevices().each { deleteChildDevice(it.deviceNetworkId) }
|
||||
}
|
||||
|
||||
private sendCommand(body) {
|
||||
//log.debug "Yamaha Network Receiver send command: ${body}"
|
||||
|
||||
def hubAction = new physicalgraph.device.HubAction(
|
||||
headers: [HOST: getReceiverAddress()],
|
||||
method: "POST",
|
||||
path: "/YamahaRemoteControl/ctrl",
|
||||
body: body
|
||||
)
|
||||
sendHubCommand(hubAction)
|
||||
}
|
||||
|
||||
private getHttpHeaders(headers) {
|
||||
def obj = [:]
|
||||
new String(headers.decodeBase64()).split("\r\n").each {param ->
|
||||
def nameAndValue = param.split(":")
|
||||
obj[nameAndValue[0]] = (nameAndValue.length == 1) ? "" : nameAndValue[1].trim()
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
private getHttpBody(body) {
|
||||
def obj = null;
|
||||
if (body) {
|
||||
obj = new XmlSlurper().parseText(new String(body.decodeBase64()))
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
private getDeviceId(zone) {
|
||||
return "yamaha|${settings.receiverIp}|${zone}"
|
||||
}
|
||||
|
||||
private getReceiverAddress() {
|
||||
return settings.receiverIp + ":80"
|
||||
}
|
||||
|
||||
private String convertIPtoHex(ipAddress) {
|
||||
return ipAddress.tokenize( '.' ).collect { String.format( '%02x', it.toInteger() ) }.join().toUpperCase()
|
||||
}
|
||||
|
||||
private String convertPortToHex(port) {
|
||||
return port.toString().format( '%04x', port.toInteger() ).toUpperCase()
|
||||
}
|
||||
Reference in New Issue
Block a user