From d651242b0e606c43969e84d8222405ee35b10622 Mon Sep 17 00:00:00 2001 From: TPMhouse <57639396+TPMhouse@users.noreply.github.com> Date: Tue, 20 Oct 2020 12:23:50 -0400 Subject: [PATCH] Update from smart things public (#1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Sinope WWST DTH update (#31140) * Sinope WWST DTH update @shrakuma There's an update following the file that your team shared with us: Sinope_issues_list_update_28_04_2020.xlsx --closed due to fingerprint unwanted modification * Modifying 'Sinope WWST DTH update' Co-authored-by: Vincent G. Beauregrad * Revert "SmartSense Motion Sensor: Use same icon as catalog for ST sensors" This reverts commit 768a1fcefb595ae8afc630f205428f425c4fd752. * ICP-12803 Add three-axis capability to multi sensor metadata (#32909) * SmartSense Motion Sensor: Use same icon as catalog for ST sensors The catalog has two entries for SmartThings motion sensors. One entry for the newest sensor and second entry for all the other sensors. The second entry uses a different motion sensor icon so we need to specify UI Metadata that also uses that same icon. https://smartthings.atlassian.net/browse/ONEAPP-27569 * WWST-6729 Added fingerprint for Inovelli Dimmer LZW31-SN (#33531) * Zigbee RGBW Bulb: Add fingerprint for sengled E1F-N5E (#33597) * ONEAPP-21574 Update device icon for Samjin SmartThings SmartPower Outlet (#32868) * ONEAPP-21574 Update device icon for Samjin SmartThings SmartPower Outlet * ONEAPP-21573 Update icons for SmartThings moisture sensors (#33681) * [DevWS] Fingerprint for iTec Home Switch (#33592) * [DevWS] Add sengled light fingerprint (#33598) * [DevWS] Add Sengled outlet fingerprint (#33596) * [WWST-5069,ICP-12456] Added FP and integrated Everspring SP815 and fixed and added parameter for Evesrping SP817 (#32967) * Added FP and integrated Everspring SP815 and fixed and added parameter for Everspring SP817 Co-authored-by: Zuzanna Wozniak/Home IoT Development (IoT) /SRPOL/Engineer/Samsung Electronics * ICP-13231- removed cause of duplicated events (#32782) * ICP-13231 removed cause of duplicated events * moved adding child devices to configure function * Moved creating child events to after adding a child * ICP-12945, ICP-13000 - fix for handling Danfoss Ally battery reports (voltage reports) * [WWST-6790] Fingerprints for DAWON devices (#33933) * Fingerprints for DAWON devices * Removed redundant else if statement * [CHAD-3909] SmartSense Multi Sensor: Add preference translations (#33923) * [WWST-6785] Fingerprint for DAWON DNS In-Wall Outlet PM-C140-ZB (#34249) * ICP-12945, ICP-13000 - fix no 2 for handling Danfoss Ally battery reports (voltage reports) * Added metadata for Sinope Load Controller (#34454) Co-authored-by: Zuzanna Wozniak/Home IoT Development (IoT) /SRPOL/Engineer/Samsung Electronics * CHAD-3909 Garage door strings were not set/translated correctly. (#34614) * [ICP-12852] Added capability 'Temperature Alarm' (#29024) * Removed 'temperatureAlarm' attribute and changed values in the tiles * Fix for sending 'temperatureAlarm - cleared' event * Added suggested changes in the updated() * Added suggested changes in updated method * Added checking if cleared alarm is not already set while forcing cleared event * Fix Co-authored-by: Zuzanna Wozniak/Home IoT Development (IoT) /SRPOL/Engineer/Samsung Electronics * WWST-2441, WWST-2448, WWST-2449, WWST-6168, WWST-6171, WWST-6172 - Custom DTH for Qubino Dimmers (DIN, Flush, Flush 0-10V) (#28554) * New DTH for Qubino Flush Dimmer 0-10V - ZMNHVD * Add associations with groups:5,6 * Shortened list of device settings * Reversed synchronization of device settings * Add a child illuminance sensor * Handle events coming from different types of inputs. Code refactoring. * Shortened list of device settings (removed settings of minimum/maximum dimming value) * WWST-2441, WWST-2448, WWST-2449, WWST-6168, WWST-6171, WWST-6172 - Custom DTH for Qubino Dimmers (DIN, Flush, Flush 0-10V) * removed child illuminance sensor * Fixes * Fixes * Fixes and workarounds, added two missed device preferences. * Fixes * Removed "boolRange" preferences boilerplate code * Fixes, corrected few options' names (for consistency sake) * even devices in different namespaces cannot share names (#34989) * Fixes for ICP-13200, ICP-13202 (#34851) * Fixes for setting device preferences properly. Removed unnecessary calls of meterGet. * Removed boolRange boilerplate code. * Fixes for setting device preferences properly.Removed boolRange boilerplate code. * Fixes for setting device preferences properly. * Fix of spacing * ICP-12967 Configure Aeotec Water Sensor to send non-MC reports to preserve local execution (#34615) * CWD Smart Dimmer Lamp Brand name:CollingWood App:zhangfangwen's smart app device type:bulb relevant information: manufacturer: "CWD" deviceJoinName: "CWD light" * CWD Smart Colour Tuneable Lamp Brand name:CollingWood App:zhangfangwen's smart app device type:bulb relevant information: manufacturer: "CWD" deviceJoinName: "CWD light" * CWD Smart RGBW Lamp Brand name:CollingWood App:zhangfangwen's smart app device type:bulb relevant information: manufacturer: "CWD" deviceJoinName: "CWD light" * [ICP-11333] Extended delay time between set and get thermostat modes commands (#34601) * [ICP-13020] EZMultipli - fix for timeouts after color change (#34180) * Fix for timeouts after color change * Added piece of code which prevents inifnite loops * CHAD-3909 Set garage sensor preference to empty string (#35341) This will be coupled with a future plugin change to add a call to action as part of the ui element. * Revert "Revert "CHAD-3849 Update SmartWeather Station Tile to support the new mobile client"" (#27246) * Revert "Revert "CHAD-3849 Update SmartWeather Station Tile to support the new mobile client"" * Update custom capability names * Update zigbee-rgbw-bulb.groovy Removed duplicated fingerprints, added missing fingerprint. * Update zigbee-dimmer.groovy Updated to current code from master branch. Removed duplicated fingerprints. * Update zigbee-dimmer.groovy Updated to current code from master branch. Removed duplicated fingerprints. * Update zigbee-dimmer.groovy Updated to current code from master branch. Removed duplicated fingerprints. * Update zigbee-dimmer.groovy Updated to current code from master branch. Removed duplicated fingerprints. * Update zigbee-white-color-temperature-bulb.groovy Updated to current code from master branch. Removed duplicated fingerprints. * Update zigbee-white-color-temperature-bulb.groovy Updated to current code from master branch. Removed duplicated fingerprints. * Update zigbee-white-color-temperature-bulb.groovy Updated to current code from master branch. Removed duplicated fingerprints. * DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Switch (#35589) Co-authored-by: 啦啦 王 * [ICP-13163] Add alarm methods to child, expose chime sounds (#34995) * Add alarm method to child, expose chime sounds * Space fix, remove if-statements * Fixes * Fixes * fixes build (#35920) * Changed deviceJoinName: Ultra Thin Wafer -> Wafer * [WWST-2444] New DTH for Qubino Flush 2 Relay (#34355) * New DTH for Qubino Flush 2 Relay * Added temperature sensor to DTH and removed not used boilerplate * fixup! Added temperature sensor to DTH and removed not used boilerplate * Quick refactoring temperature sensor child device initialization * Renamed temperature sensor's DTH * Removed offlinePingable flag, changed zwaveEvent method call * WWST-6827 - Leviton 4 Speed Fan Controller (#35590) * Added fingerprint and 4-speed device handling * Added method for getting max supported speeds * Added mnmn and vid, other fixes * Method name, redundant conditional statement - fixes * WWST-6841, WWST-6837 Add two Schlage locks (#36081) * WWST-6935 Fingerprints for Aoetec Door Window Sensor 7 Pro (#36264) * [WWST-6921] New DTH Z-Wave Water/Temp/Humidity Sensor (#36265) * New DTH Z-Wave Water/Temp/Humidity Sensor * Added generic metadata for whole DTH, improved code readability * WWST-6822 Leviton Tamper Resistant Outlet ZW15R (#35995) * Fingerprint for Leviton Outlet ZW15R * Changed dth * Spacing * ICP-13040 Change zigbee devices to report decimal temperature (#36278) This accompanies hubcore and appengine-zigbee changes to allow the parsing and reporting of temperature values as floats. * ICP-13330 new UI Metadata for Qubino Temperature Sensor (#36801) * ICP-13368 Specified metadata for Sinope TH1500ZB (#36733) * [ICP-13365] Added Tamper Alert for Aeotec Door/Window Sensor 7 Pro (#36732) * Added Tamper Alert for Aeotec Door/Window Sensor 7 Pro * Actual tamper reports handler * Added initial tamper event * ICP-11324 - new UI Metadata for Sylvania LIGHTIFY Edge-lit flushmount (#36894) * Fixed 'parseAduroSmartButtonMessage' function in zigbee-mulit-button.groovy (#36892) Fixed 'parseAduroSmartButtonMessage' function in zigbee-mulit-button.groovy file, the bug that there will be multiple events when pressing a button. other file not change, only want merge zigbee-mulit-button.groovy . Co-authored-by: Andy Yi * ICP-12929 Standardize how Fibaro preference default text is created (#36909) * ICP-12929 Standardize how Fibaro preference default text is created There was an existing pattern to to print the enum value of a preference rather than the raw enum, so I've just adopted it across all the fibaro DTHs that were using the incorrect method. * fixup * [WWST-6165] New DTH for Qubino Flush Shutter (#36082) * New DTH for Qubino Flush Shutter * Deleted Switch Level capability, changed refresh() method, reworded preferences descriptions * Removed unnecessary import statement, added child switch multilevel DTH * CHAD-5256 Update child DNIs when the parent rejoins (#36908) * CHAD-5256 Update child DNIs when the parent rejoins * [ICP-8763] Zigbee Metering Plug: Prevent duplicate switch events (#36353) Zigbee Metering Plug: Prevent duplicate switch events * issue fix : ICP-12604: Supported temperature values ​​for the following options. (#35327) @shrakuma ICP-12604: Supported temperature values ​​for the following options. - Ambient limit - 5-36 degrees in Celsius, or 41-96 degrees in Fahrenheit. - Floor high limit - 5-36 degrees in Celsius, or 41-96 degrees in Fahrenheit. - Floor low limit - 5-36 degrees in Celsius, or 41-96 degrees in Fahrenheit. In the ST application, we can enter from 5-96 (from 5 degrees Celsius to 96 degrees Fahrenheit) → this is confusing. Sinope thermostats support Celsius and Fahrenheit unit systems - this option can be changed manually on the device. Co-authored-by: Vincent G. Beauregrad * Fingerprint for Ajax Online RGBCCT (#37167) * DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Multi Switch (#37787) * DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Multi Switch * Update zigbee-multi-switch.groovy Updated comments with "Raw Description" * Update zigbee-multi-switch.groovy Fix of spacing Co-authored-by: 啦啦 王 Co-authored-by: Konrad K <33450498+KKlimczukS@users.noreply.github.com> * DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Switch (#35158) Co-authored-by: 啦啦 王 * ICP-13140 For IKEA blinds return the current state of the blinds when pause is called if the blinds are not moving (#38018) * ICP-13140 For IKEA blinds return the current state of the blinds when pause is called if the blinds are not moving * Always send pause command over Zigbee * Fix "display" -> "displayed" in sendEvent * CHAD-5172 Send follow-ups to verify that window shade level changes o… (#36279) * CHAD-5172 Send follow-ups to verify that window shade level changes occurred We noticed what seems to be a device bug when window shades send us unsolicited battery reports at the same time they are told to open/close. This seems to cause them to send us immediate position updates rather than waiting until the action is completed. This change should send periodic gets until we see the value we want, up to 5 times, or about 25s after the intial command. * fixup * logic changes * guarantee overwrite * state variables do not work with += operator * add a +/- 2 range for the level * spacing fix and re-arrange logic * CHAD-5280 Cap number of battery queries (#37869) * CHAD-5280 Cap number of battery queries Locks will query for battery state after a battery replace event, but in some cases, the lock will go offline before responding resulting in an infinite loop of querying the battery, which can clog the z-wave message queue. * state variables do not work with += operator * this should break any existing devices out of the loop * fixup * [WWST-2446_2447] Add Qubino Relay 1/1D to existing DTH (#37124) * Add Qubino Relay 1/1D to existing DTH * [ICP-13246] Stelpro Thermostats preferences changes (#32881) * Changes to Stelpro preferences * fixup! Changes to Stelpro preferences * Copied 'secondsPast' method from another DTH. * Switched back to old logic, with new preference description and events time inverval * Forcing to show every changig current state event * Revert "Forcing to show every changig current state event" This reverts commit 7077e0e2e36baf25fd1ed4d403881b88b3847192. * Minor fixes * Comment change * [ICP-13322, ICP-13326, ICP-13336, ICP-13345, ICP-13346, ICP-13355] - fixes for Qubino Dimmers (#37228) * fixes: ICP-13322, ICP-13326, ICP-13355 * fixes2: ICP-13322, ICP-13326, ICP-13355 * fixes3: ICP-13322, ICP-13326, ICP-13355 * fix for ICP-13345 - add meterGet commands * Fix for adding elements to commands collection * ICP-13336 - Removed option 3, because it does not apply to Qubino Temperature Sensor ZMNHEA1. * Added fingerprint for Ajax Online Filament Bulb (#38132) * CHAD-5256 Hotfix to update child DNIs of zigbee-multi-switch (#38146) * CHAD-5256 change re-addressing code There was more code using the leading 0 of child devices than I first noticed, so the leading zero in the child DNI has simply been re-added. * adds a fix for devices that were migrated while this bug was active. * add code to avoid a bug encountered if installed and updated are called in succession * ICP-13392 Added fingerprints of device with updated firmware alongside one configuration command (#38227) * 'displayed' flag set to false for configuration event (#21920) * [WWST-6159] Qubino Flush Shutter DC - fingerprint and improvements (#38295) * Added fingerprint for Qubino Flush Shutter DC * Opening/closing report also for manual actions * [ICP-13423] Qubino Flush 2 Relay - Added initial poll (#38316) * WWST-6946 Somfy Glydea Ultra fingerprint (#38386) * DevWS add fingerprint for Ecolink DWZB1-ECO door/window sensor (#38312) * ICP-12883,ICP-12849, ICP-12851 - Add mnmn and VID to: Dome DMMS1 and NEO Coolcam Motion Light Sensor fingerprints (#30195) * ICP-12883 - added mnmn and VID to Dome Motion/Light Sensor DMMS1 fingerprint * ICP-12883 - Device specific VID in Dome Motion/Light Sensor DMMS1 fingerprint * ICP-12849, ICP-12851 - Add mnmn and a device specific VID to NEO Coolcam Motion/Light Sensor fingerprints * ICP-10928 - Zigbee RGBW Bulb: Fix color temperature value on initial join, code refactoring. (#30421) Set the color temperature to 5000K on initial join. 5000K was chosen because it is one of the values that is doesn't change when converted to mireds and back again and because it is in the supported range of all the devices that have fingerprints in this DTH. The code was also refactored to make more use of the Zigbee library. * Handled values for energy and power events * WWST-6286 Added fingerprint and some tweaks for Aeotec Radiator Thermostat (#38798) * CHAD-5336 Make sure that temperature offset calculations for Zigbee devices are correct and rounded to one decimal (#38946) * SmartPower Outlet: Fix icon for the outletv4 https://smartthings.atlassian.net/browse/ONEAPP-31381 * ICP-13200 - longer delay between BasicSet and BasicGet commands (#38875) * Add fingerprint for CST thermostat Honeywell T6 Pro (#39100) * CHAD-5355 Zigbee lock event de-duplication (#39101) * Uses logic similar to what we do in z-wave locks to delay events created from lock attribute reports in case we receive a much more detailed operation event later. If the operation event is sent first, the lock attribute event will be marked as not displayed. * always delay lock attribute reports * add log message * fixup * fixup * WWST-6984,WWST-6989,WWST-6994 Fingerprints for Dawon Power Manager Smart Switches (US) (#39724) Co-authored-by: Zuzanna Wozniak/Home IoT Development (IoT) /SRPOL/Engineer/Samsung Electronics * CHAD-4340 Update Window Shade devices to use Window Shade Level (#30151) * update parseAduroSmartButtonMessage function (#40488) Some customers reported that the buttons 1 and 4 are not sensitive, so restore the zigbee.ONOFF_CLUSTER event trigger of button 1 and button 4, which will increase the success rate of event reporting after the button is pressed Co-authored-by: Andy Yi * [ICP-13162] Add alarm event when tamper is triggered (#36895) * Add alarm event when tamper is triggered * Add off event * Fixes * Change time in runIn method, add chime off event * Revert "CHAD-4340 Update Window Shade devices to use Window Shade Level (#30151)" This reverts commit 878f39a6264343bce15816219454c229f545c8e4. * WWST-7064 - Fingerprint for Innr EU Smart Plug SP 220 * WWST-7065 - Fingerprint for Innr Smart Color Bulb E26 AE 280 C * WWST-7066, WWST-7067, WWST-7068 - Fingerprints for Innr Smart Outdoor Flex Light 2m Colour OFL 120 C, Innr Smart Outdoor Flex Light 4m Colour OFL 140 C, Innr Smart Outdoor Spot Light Colour OSL 130 C * [ICP-13444] Delete child switches on Flush Relay 1/1D (#40329) * Delete child switches on Flush Relay 1/1D * Aeon hem gen5 association fix and Configuration update (#40990) * Resolve association issue and updated Parameters Resolved association Group 1 association to Node ID 01, ensures HEM Gen5 is properly associated - Line 142 (delete node association) - Line 143 (reassign SmartThings to Association Group 1) Parameter settings (Line 162 - 167) to report kWh and Watt total every 300 seconds. Selective reporting disabled - Param 101 = 3 - Param 102 = 0 - Param 103 = 0 - Param 111 = 300 - Param 90 = 0 - Param 13 = 0 * Change definition name back to default Line 20 * [ICP-13278] Added preferences for Aeotec Nano Dimmer to adjusting the dimmer level (#37125) * Added preferences for Aeotec Nano Dimmer to adjusting the dimmer level * Added requested changes * Changed name of the method * Fix * Updated the description of the needed preference and removed unnecessary one * Fix Co-authored-by: Zuzanna Wozniak/Home IoT Development (IoT) /SRPOL/Engineer/Samsung Electronics * [ICP-13555] EZEX power meter patch. (#41807) [ICP-13555] EZEX power meter patch. * [ICP-13555] EZEX power meter patch #2. [ICP-13555] EZEX power meter patch #2. * Somfy Sonesse fingerprint * [WWST-6729] DTH for Inovelli Dimmer LZW31-SN (#37229) * Added fingerprint for Inovelli Dimmer LZW31-SN * WWST-6729 Added mcd dth for Inovelli Dimmer LZW31-SN * removed old reference to Inovelli Dimmer * Changed child dth name, fixed formatting, removed unnecessary capabilities, fixed child dni * Added configure method, fixed parameters range, fixed formatting * Removed unecessary parameters * Deleted LED Bar color preference from settings view, shortened delay between commands * Level event is created on every level change * Deleted minHubCoreVersion added mnmn * Added child buttons * Changed button event from up/down to pushed, button labels and supported values. Deleted unnecessary code. * Fixed energy rounding * ICP-11574 - query device for current status in response to WakeUpNotification (#42036) * ICP-11574 - query device for current status in response to WakeUpNotification * WWST-6725 Added fingerprint for Inovelli Dimmer LZW31 (#42221) * CHAD-5236 CHAD-5235 Add translation strings for Fibaro Smoke & Z-Wave Siren (#42146) * CHAD-5236 Add translation strings for Z-Wave Siren * CHAD-5235 Add translation strings for Fibaro Smoke Sensor * update in response to testing and verification * DevWs for Ajaxonline Ltd containing containing ZigBee RGBW Bulb (#42713) * DevWs for Ajaxonline Ltd containing containing ZigBee RGBW Bulb * Update zigbee-rgbw-bulb.groovy I fixed spacing (4 spaces -> 1 tab) Co-authored-by: Konrad K <33450498+KKlimczukS@users.noreply.github.com> * ONEAPP-33322 Update range for tempOffset preference * ICP-11574 - Query device for current status in response to WakeUpNotification (#42710) * WWST-5667_2 - check if device is SOMFY, code refactoring. (#42726) * CHAD-5235 Hotfix en-uk is not a valid language code. this was due to manual editing on my part * CHAD-5235 CHAD-5236 Spot fixes for translations Programmatic default values are overwritten by "Tap to set" in DM if they have not yet been set and "tap to set" is not translated. Fixes missing period that was preventing the application of translations. * [WWST-4667] Qubino 3 Phase Meter integration (#43205) * New DTHes to support Qubino 3 Phase Meter * Added raw description, changed child device DTH other minor fixes * ICP-13360 Qubino Dimmer: Addded querying the device about meter values in basic report handling (#42729) * [WWST-6748] Fingerprint for Yale Fingerprint Lock YMF40 (#43641) * C2C-1064 Update Ecobee notify text * CHAD-5382 Prepare Z-Wave Battery Thermostat for Local Execution (#43642) * CHAD-5382 Prepare Z-Wave Battery Thermostat for Local Execution Adds the Humidity Measurement capability that was being populated but not declared Sets the hubcore version required for local thermostat execution. Removes unused "currentSetpoint" attribute that was cruft from battery-less DTH * [ICP-13584; ICP-13551] Fingerprint change for Somfy Glydea, pause() method tweak (#43795) * WWST-6945 - support for Somfy Situo 4 Zigbee Pure (#43628) * WWST-6945 - support for Somfy Situo 4 Zigbee Pure * [ICP-13278] Changed minimum dimmer level range in settings for Aeotec Nano Dimmer (#43964) Co-authored-by: Zuzanna Wozniak/Home IoT Development (IoT) /SRPOL/Engineer/Samsung Electronics * update smartsense-motion-sensor.groovy (#44143) update smartsense-motion-sensor.groovy,Optimize that deviceJoinName,change the vid to generic-motion-2 Co-authored-by: Andy Yi * ICP-11574 Manually set smoke alarm wakeup interval to 4 hours (#44128) * ICP-11574 Manually set smoke alarm wakeup interval to 4 hours * don't set wakeupinterval for first alert, since there is legacy behavior * Z-Wave Basic Window Shade fix + Calibration (#44034) * Z-Wave Basic Window Shade fix + Calibration - Open() and Close() buttons resolved - Calibration Parameter setting included in preference * Fix of requested issues - Return pair name to "Aeotec Window Treatment" - Fixed spacing of lines 61 - 73 - Removed else block on line 171 * Fixed Requested issues - Fixed indentation to use tabs. (line 165) - Fixed range instead of the use of text. (line 69) * Update Part 3 - Nano Shutter - used calibrationTime rather than int Time. (Line 164) - Condensed preference input for "calibrationTime" - Added note on top of calibrationTime to indicate it is specific to Nano Shutter and the function its used in. * Update Nano Shutter Part 4 - Added case "open": on line 117 case "close": on line 121 * DevWs for CoolKit Technology Co.,Ltd containing containing ZigBee Switch (#41408) Co-authored-by: 啦啦 王 * ONEAPP-33321 Update Korean translations (#44467) * ICP-13664, ICP-13665 Deleted old fingerprint for Inovelli Dimmer LZW31-SN (#45024) * WWST-7022 Added fingerprint for POPP Strike Lock Control (#45045) * [CHAD-5501][zigbee multi switch] Need Exception handling for eZEX multi switch (#44306) * Exception handling for eZEX * Change the logic * ICP-13694 - removes supporting the Battery capability (#45566) * ICP-13694 - removes supporting the Battery capability * ICP-13694 - removes supporting the Battery capability * reverts innr fingerprint (#45829) * CHAD-5290 Move Schlage BR469ZP fingerprint (#45988) Because this device reports door lock operation events prior to notification events, lock code events are generated without the necessary user code data. This was causing user-code based automations to not fire. Since this device executes locally, it would have required a high-risk fix in hubcore. Rather than removing the device entirely, we are moving it to a DTH where user codes would not be accessible for the purposes of creating automations. * ICP-13566/ICP-13565 Change metadata for Qubino 1D (#45982) * [WWST-6516] New DTHes to cover Fibaro Walli Roller Shutter functionality (#30258) * New DTHes to cover Fibaro Walli Roller Shutter functionality * Added Child Venetian Blind DTH and changed namespace * Further fixes for bugs discovered during work with similar device * Ongoing work Fibaro Walli Roller Shutter * Added Window Shade Level capability * [ICP-13618] Qubino Flush 2 Relay - energy usage is not reported (#43446) * Added daily energy usage report * Changes in getEnergyUsage method * Moved to querying energy usage after power report * C2C-1027 Ecobee Capability Migration in Groovy integration Adding discrete thermostat capabilities to prepare migration to st-schema integration * CHAD-5488 Update Keen Home Smart Vent (#45127) * CHAD-5488 Update Keen Home Smart Vent includes a workaround for a bug introduced in newer vent FWs adds the draft atmospheric pressure measurement capability instead of custom attributes if the vent detects it is obstructed, it will attempt to clear its obstruction automatically * update obstruction detection * fixes and update to obstruction detection * fixup * rework configuration flow * fixup * remove obstruction handling * CHAD-5555 Update z-wave device multichannel to work in oneapp (#46568) * CHAD-5555 Update z-wave device multichannel to work in oneapp Because of its variable number of components, the child devices cannot be added as components. * add updated method to convert legacy implementations * Recessed Door Sensor 7 device type update (#46572) * Update def configure() Lines 136 - 140 - configure Recessed Door Sensor 7 upon pairing to enable Binary Sensor Report - fixes issue where Open/Close status does not update when paired using S2 Authentication * Update state check Line 137 changed to zwaveInfo.mfr == "0371" && zwaveInfo.model == "00BB" * DevWs for DAWON DNS containing containing Zigbee Metering Plug and 2 more (#43376) * DevWs for DAWON DNS containing containing Zigbee Metering Plug and 2 more * 1. Changed deviceJoinName(ST Dawon Outlet -> Dawon Outlet). 2. Changed the structure of getEnergyDiv(). 3. Added isDawonOutlet() . * re-coding * Changed deviceJoinName. * re-coding * Changed deviceJoinName * original Public DTH * add * master DTH * Update zigbee-metering-plug.groovy Add Dawon Outlet * Update zigbee-switch.groovy remove empty line * Update zigbee-multi-switch.groovy remove empty line * Update zigbee-metering-plug.groovy remove command "reset" * Update zigbee-metering-plug.groovy remove empty line * Update zigbee-switch.groovy remove empty line * Update zigbee-switch.groovy * Update zigbee-metering-plug.groovy remove reset Co-authored-by: 남수 허 * WWST-6752 Fingerprint for Yale Fingerprint Lock YDF40 (#43948) * ICP-13708 Added proper fingerprint for Yale YMF40 (#46734) * DevWs for DAWON DNS containing containing Zigbee Metering Plug and 2 more (#43376) * DevWs for DAWON DNS containing containing Zigbee Metering Plug and 2 more * 1. Changed deviceJoinName(ST Dawon Outlet -> Dawon Outlet). 2. Changed the structure of getEnergyDiv(). 3. Added isDawonOutlet() . * re-coding * Changed deviceJoinName. * re-coding * Changed deviceJoinName * original Public DTH * add * master DTH * Update zigbee-metering-plug.groovy Add Dawon Outlet * Update zigbee-switch.groovy remove empty line * Update zigbee-multi-switch.groovy remove empty line * Update zigbee-metering-plug.groovy remove command "reset" * Update zigbee-metering-plug.groovy remove empty line * Update zigbee-switch.groovy remove empty line * Update zigbee-switch.groovy * Update zigbee-metering-plug.groovy remove reset Co-authored-by: 남수 허 * ICP-12798 Update Doorbell Siren 6 to support Sound/Volume control (#44305) * Update aeotec-doorbell-siren-6.groovy - Added setting/preference option to configure volume/sound via Multichannel Cmd Encap (Sound Switch Configuration SET) * Update code format Format fixes - zwave command classes use hex values for their input - device preferences and def variables changed to have initial lowercase letters - open braces are now on same line as if statements - closing braces are now on the same line as following else statements - fixed minor formatting issues Code change - separated multichannel encap as mcEncap() and encap() to handle Multichannel Cmd Encap (Sound Switch Configuration Set) separately * Quick update Remove 0x79: 1 from secureencapsulation and encapsulation. * Condense private mcEncap() Condensed code to use response(cmd) for MC Cmd Encap (Sound Switch Config SET). * just a comment edit Non-essential commit, changed commend on line 336 * added return to line 336 - Add return in front of line 336 * Final update for minor changes - Changed steps in description on line 57 for better user flow. * Fixed child device status update - Fixed issue where child devices were not updating. Button press and tamper child devices now change states. - Edited Line 162 -164 to set state.lastTriggeredSound when a new sound is playing from a different endpoint. * CHAD-5552, CHAD-5553, CHAD-5554 Update legacy MCD devices to properly work as MCD (#47247) * CHAD-5552, CHAD-5553, CHAD-5554 Update legacy MCD devices to properly work as MCD * Logic updates * DevWs for HAB Home Intelligence containing containing iblinds v3 (#42736) * DevWs for HAB Home Intelligence containing containing iblinds v3 * Bring v3 code in to other DTH and protect with device model check * Remove extra space. Ooops! * Fix exceptions * Add protection against exceptions when configuring Co-authored-by: Eric Barnett Co-authored-by: Donald Kirker * ICP-13708 Fixed typo in module name (#47261) * [ICP-13411] Qubino Flush Shutter - energy usage is not reported (#42222) * Schedule energy usage poll once a day * Moved to querying energy usage after power report * WWST-7143 - changes deviceJoinName to WAFER. Co-authored-by: Steven Green Co-authored-by: SmartThings, Inc Co-authored-by: Vincent G. Beauregrad Co-authored-by: Tom Manley Co-authored-by: Donald Kirker Co-authored-by: MWierzbinskaS <43334596+MWierzbinskaS@users.noreply.github.com> Co-authored-by: sxl1987 <54304618+sxl1987@users.noreply.github.com> Co-authored-by: iTecHome <60195057+iTecHome@users.noreply.github.com> Co-authored-by: ZWozniakS <48519140+ZWozniakS@users.noreply.github.com> Co-authored-by: Zuzanna Wozniak/Home IoT Development (IoT) /SRPOL/Engineer/Samsung Electronics Co-authored-by: Konrad Klimczuk Co-authored-by: PKacprowiczS <41617389+PKacprowiczS@users.noreply.github.com> Co-authored-by: BJanuszS <61963402+BJanuszS@users.noreply.github.com> Co-authored-by: Konrad K <33450498+KKlimczukS@users.noreply.github.com> Co-authored-by: Zhang Fangwen Co-authored-by: 啦啦 王 Co-authored-by: MGoralczykS <42434140+MGoralczykS@users.noreply.github.com> Co-authored-by: ADUROSMART ERIA <52692745+adurosmart@users.noreply.github.com> Co-authored-by: Andy Yi Co-authored-by: jwg-123 <51741592+jwg-123@users.noreply.github.com> Co-authored-by: Bartlomiej Janusz/Home IoT Development (IoT) /SRPOL/Associate/Samsung Electronics Co-authored-by: Aeotec-ccheng <63321041+Aeotec-ccheng@users.noreply.github.com> Co-authored-by: Juhaki Park <37175353+juhaki@users.noreply.github.com> Co-authored-by: Ajax Online <56229160+Ajax-online@users.noreply.github.com> Co-authored-by: Vinay Rao <3150991+workingmonk@users.noreply.github.com> Co-authored-by: Taejun Park Co-authored-by: ingvar.marstorp Co-authored-by: dwd-kwon <59678391+dwd-kwon@users.noreply.github.com> Co-authored-by: 남수 허 Co-authored-by: habhomegit <42719976+habhomegit@users.noreply.github.com> Co-authored-by: Eric Barnett --- .githooks/pre-commit | 22 + build.gradle | 14 + .../axis/axis-gear-st.src/axis-gear-st.groovy | 13 +- .../drzwave/ezmultipli.src/ezmultipli.groovy | 30 +- .../inovelli-2-channel-smart-plug-mcd.groovy | 303 ++++ .../inovelli-2-channel-smart-plug.groovy | 45 +- .../fibaro-co-sensor-zw5.groovy | 26 +- .../fibaro-dimmer-2-zw5.groovy | 38 +- .../fibaro-door-window-sensor-2.groovy | 65 +- ...-window-sensor-zw5-with-temperature.groovy | 4 +- .../fibaro-door-window-sensor-zw5.groovy | 7 +- .../fibaro-double-switch-2-zw5.groovy | 32 +- .../fibaro-flood-sensor-zw5.groovy | 35 +- .../fibaro-motion-sensor-zw5.groovy | 28 +- .../fibaro-single-switch-2-zw5.groovy | 42 +- .../fibaro-wall-plug-eu-zw5.groovy | 21 +- .../fibaro-wall-plug-us-zw5.groovy | 24 +- .../fibaro-walli-dimmer-switch.groovy | 465 ++++++ .../fibaro-walli-double-switch.groovy | 504 ++++++ .../fibaro-walli-roller-shutter-driver.groovy | 531 ++++++ ...ibaro-walli-roller-shutter-venetian.groovy | 617 +++++++ .../fibaro-walli-roller-shutter.groovy | 554 +++++++ .../iblinds-zwave.src/iblinds-zwave.groovy | 357 ++++ .../keen-home-smart-vent.groovy | 503 +----- .../osotech/plantlink.src/plantlink.groovy | 2 +- .../spruce-controller.groovy | 6 +- .../spruce-sensor.src/spruce-sensor.groovy | 14 +- .../qubino-3-phase-meter.groovy | 195 +++ .../qubino-dimmer.src/qubino-dimmer.groovy | 652 ++++++++ .../qubino-flush-2-relay.groovy | 480 ++++++ .../qubino-flush-shutter.groovy | 501 ++++++ .../qubino-temperature-sensor.groovy | 52 + .../rachio-iro2-zone.groovy | 495 +----- .../rooms-beautiful-curtain.groovy | 295 ++++ .../i18n/messages.properties | 2 + .../samsung-smart-doorlock.groovy | 2 +- .../dm2500zb-sinope-dimmer.groovy | 61 +- .../rm3250zb-sinope-load-controller.groovy | 72 +- .../sw2500zb-sinope-switch.groovy | 67 +- ...th1123zb-th1124zb-sinope-thermostat.groovy | 412 ++--- .../th1300zb-sinope-thermostat.groovy | 377 ++--- .../th1400zb-sinope-thermostat.groovy | 348 ++-- .../th1500zb-sinope-thermostat.groovy | 285 +--- .../va4200wz-va4200zb-sinope-valve.groovy | 63 +- ...00s-wl4200-sinope-water-leak-sensor.groovy | 63 +- .../Orvibo-Contact-Sensor.groovy | 12 +- .../i18n/messages.properties | 17 + .../aeon-home-energy-meter.groovy | 25 +- .../aeon-illuminator-module.groovy | 2 +- .../aeon-key-fob.src/aeon-key-fob.groovy | 9 +- .../aeon-led-bulb-6.groovy | 5 +- .../aeon-led-bulb.src/aeon-led-bulb.groovy | 4 - .../aeon-minimote.src/aeon-minimote.groovy | 8 +- .../aeon-multisensor-6.groovy | 12 +- .../aeon-multisensor-gen5.groovy | 4 +- .../aeon-multisensor.groovy | 2 +- .../aeon-multiwhite-bulb.groovy | 10 +- .../aeon-outlet.src/aeon-outlet.groovy | 2 +- .../aeon-siren.src/aeon-siren.groovy | 2 +- .../aeon-smartstrip.groovy | 10 +- .../aeotec-doorbell-siren-6.groovy | 353 ++++ .../aeotec-doorbell-siren-child.groovy | 72 + .../aeotec-wallmote.groovy | 58 +- .../arrival-sensor-ha.groovy | 3 +- .../i18n/messages.properties | 3 +- .../arrival-sensor.src/arrival-sensor.groovy | 6 +- .../centralite-thermostat.groovy | 2 +- .../child-button.src/child-button.groovy | 2 +- .../child-color-control.groovy | 37 + .../child-contact-sensor.groovy | 57 + .../child-energy-meter.groovy | 50 + .../child-switch-multilevel.groovy | 39 + .../child-temperature-sensor.groovy | 1 + .../child-venetian-blind.groovy | 33 + .../cree-bulb.src/cree-bulb.groovy | 2 +- .../ct100-thermostat.groovy | 6 +- .../smartthings/danalock.src/danalock.groovy | 2 +- .../dawon-zwave-smart-plug.groovy | 4 +- .../dawon-zwave-wall-smart-switch.groovy | 374 +++++ .../dimmer-switch.src/dimmer-switch.groovy | 6 +- .../eaton-5-scene-keypad.groovy | 2 +- .../eaton-accessory-dimmer.groovy | 2 +- .../eaton-anyplace-switch.groovy | 2 +- .../ecobee-thermostat.groovy | 6 + .../ecolink-water-freeze-sensor.groovy | 2 +- .../ecolink-wireless-siren.groovy | 10 +- .../ecolink-zigbee-water-freeze-sensor.groovy | 4 +- .../econet-vent.src/econet-vent.groovy | 4 +- .../ecosmart-4button-remote.groovy | 215 +++ .../everspring-flood-sensor.groovy | 2 +- .../everspring-illuminance-sensor.groovy | 2 +- .../everspring-st814.groovy | 10 +- .../ezex-smart-electric-switch.groovy | 2 +- .../i18n/messages.properties | 1 + .../ezex-temp-humidity-sensor.groovy | 8 +- .../i18n/messages.properties | 194 +++ .../fibaro-dimmer.src/fibaro-dimmer.groovy | 2 +- .../fibaro-door-window-sensor.groovy | 14 +- .../fibaro-flood-sensor.groovy | 16 +- .../fibaro-heat-controller.groovy | 32 +- .../fibaro-motion-sensor.groovy | 4 +- .../fibaro-rgbw-controller.groovy | 1056 ++++++------ .../fibaro-smoke-sensor.groovy | 83 +- .../i18n/messages.properties | 1463 +++++++++++++++++ .../fidure-thermostat.groovy | 6 +- .../fortrezz-water-valve.groovy | 4 +- .../ge-link-bulb.src/ge-link-bulb.groovy | 6 +- .../glentronics-connection-module.groovy | 2 +- .../home-energy-meter.groovy | 4 +- .../homeseer-multisensor.groovy | 2 +- .../ikea-button.src/ikea-button.groovy | 119 +- .../ikea-motion-sensor.groovy | 2 +- .../inovelli-dimmer.groovy | 585 +++++++ .../leaksmart-water-sensor.groovy | 4 +- .../lifx-color-bulb.groovy | 253 --- .../lifx-white-bulb.groovy | 178 -- .../light-sensor.src/light-sensor.groovy | 2 +- .../mimolite-garage-door-controller.groovy | 2 +- .../motion-detector.groovy | 4 +- .../nyce-motion-sensor.groovy | 6 +- .../nyce-open-closed-sensor.groovy | 12 +- .../open-closed-sensor.groovy | 2 +- .../i18n/messages.properties | 17 + .../orvibo-Moisture-Sensor.groovy | 11 +- .../Orvibo-Gas-detector.groovy | 5 +- .../i18n/messages.properties | 18 + .../i18n/messages.properties | 17 + .../ozom-smart-siren.groovy | 84 +- .../philio-multiple-sound-siren.groovy | 2 +- .../plant-link.src/plant-link.groovy | 4 +- .../qubino-flush-thermostat.groovy | 6 +- .../rgbw-light.src/rgbw-light.groovy | 314 ++-- .../secure-dimmer.src/secure-dimmer.groovy | 2 +- .../smartalert-siren.groovy | 4 +- .../smartpower-dimming-outlet.groovy | 2 +- .../smartpower-outlet-v1.groovy | 2 +- .../i18n/messages.properties | 2 + .../smartpower-outlet.groovy | 31 +- .../i18n/messages.properties | 101 ++ .../smartsense-button.groovy | 4 +- .../i18n/messages.properties | 112 ++ .../smartsense-garage-door-multi.groovy | 30 +- .../i18n/messages.properties | 112 ++ ...martsense-garage-door-sensor-button.groovy | 6 +- .../i18n/messages.properties | 105 +- .../smartsense-moisture-sensor.groovy | 19 +- .../smartsense-moisture.groovy | 8 +- .../i18n/messages.properties | 111 +- .../smartsense-motion-sensor.groovy | 64 +- .../smartsense-motion.groovy | 6 +- .../i18n/messages.properties | 260 ++- .../smartsense-multi-sensor.groovy | 60 +- .../i18n/messages.properties | 112 ++ .../smartsense-multi.groovy | 35 +- .../i18n/messages.properties | 112 ++ .../smartsense-open-closed-sensor.groovy | 32 +- .../i18n/messages.properties | 210 +++ .../smartsense-temp-humidity-sensor.groovy | 41 +- .../i18n/messages.properties | 112 ++ .../smartsense-virtual-open-closed.groovy | 6 +- ...ty.stsmartweather.apparentTemperature.json | 32 + ...ility.stsmartweather.astronomicalData.json | 91 + ...pability.stsmartweather.precipitation.json | 31 + ...apability.stsmartweather.smartWeather.json | 21 + ...stsmartweather.ultravioletDescription.json | 21 + ...apability.stsmartweather.weatherAlert.json | 35 + ...bility.stsmartweather.weatherForecast.json | 63 + ...ability.stsmartweather.weatherSummary.json | 35 + ...pability.stsmartweather.windDirection.json | 21 + .../capability.stsmartweather.windSpeed.json | 27 + .../smartweather-station-tile.groovy | 77 +- .../springs-window-fashions-remote.groovy | 6 +- .../springs-window-fashions-shade.groovy | 44 +- .../temperature-sensor.groovy | 2 +- .../simulated-device-preferences.groovy | 71 +- .../simulated-rgbw-bulb.groovy | 2 +- .../i18n/messages.properties | 112 ++ .../tyco-door-window-sensor.groovy | 8 +- .../zigbee-accessory-dimmer.groovy | 4 +- .../zigbee-battery-accessory-dimmer.groovy | 6 +- .../zigbee-button.src/zigbee-button.groovy | 8 +- .../i18n/messages.properties | 17 + .../zigbee-co-sensor.groovy | 5 +- .../zigbee-dimmer-power.groovy | 10 +- .../zigbee-dimmer-with-motion-sensor.groovy | 2 +- .../i18n/messages.properties | 1 + .../zigbee-dimmer.src/zigbee-dimmer.groovy | 138 +- .../zigbee-lock-without-codes.groovy | 18 +- .../zigbee-lock.src/zigbee-lock.groovy | 52 +- .../i18n/messages.properties | 5 + .../zigbee-metering-plug.groovy | 74 +- .../i18n/messages.properties | 15 + .../zigbee-motion-detector.groovy | 7 +- .../i18n/messages.properties | 207 +++ .../zigbee-motion-temp-humidity-sensor.groovy | 12 +- .../i18n/messages.properties | 16 + .../zigbee-multi-button.groovy | 115 +- .../zigbee-multi-switch-power.groovy | 2 +- .../i18n/messages.properties | 6 + .../zigbee-multi-switch.groovy | 139 +- .../i18n/messages.properties | 17 + .../zigbee-non-holdable-button.groovy | 196 +++ .../i18n/messages.properties | 1 + .../zigbee-plugin-motion-sensor.groovy | 2 +- .../i18n/messages.properties | 1 + .../zigbee-power-meter.groovy | 21 +- .../zigbee-range-extender.groovy | 7 +- .../zigbee-rgb-bulb.groovy | 6 +- .../zigbee-rgbw-bulb.groovy | 121 +- .../i18n/messages.properties | 21 + .../zigbee-scene-keypad.groovy | 79 +- .../i18n/messages.properties | 18 + .../zigbee-smoke-sensor.groovy | 9 +- .../zigbee-sound-sensor.groovy | 6 +- .../zigbee-switch-power.groovy | 30 +- .../i18n/messages.properties | 9 + .../zigbee-switch.src/zigbee-switch.groovy | 76 +- .../zigbee-thermostat.groovy | 116 +- .../zigbee-valve.src/i18n/messages.properties | 1 + .../zigbee-valve.src/zigbee-valve.groovy | 6 +- ...zigbee-white-color-temperature-bulb.groovy | 103 +- .../zigbee-window-shade-battery.groovy | 34 +- .../i18n/messages.properties | 3 + .../zigbee-window-shade.groovy | 70 +- .../zll-dimmer-bulb.groovy | 59 +- .../zll-rgb-bulb.src/zll-rgb-bulb.groovy | 6 +- .../zll-rgbw-bulb.src/zll-rgbw-bulb.groovy | 66 +- ...-white-color-temperature-bulb-5000k.groovy | 22 +- .../zll-white-color-temperature-bulb.groovy | 40 +- .../zooz-4-in-1-sensor.groovy | 118 +- .../zooz-multisiren.groovy | 4 +- .../zooz-power-strip.groovy | 12 +- .../zwave-basic-heat-alarm.groovy | 4 +- .../zwave-basic-smoke-alarm.groovy | 25 +- .../zwave-basic-window-shade.groovy | 195 +++ .../zwave-battery-thermostat.groovy | 110 +- .../zwave-button.src/zwave-button.groovy | 13 +- .../zwave-controller.groovy | 2 +- .../zwave-device-multichannel.groovy | 17 +- .../zwave-dimmer-switch-generic.groovy | 56 +- .../i18n/messages.properties | 112 ++ .../zwave-door-temp-sensor.groovy | 12 +- .../zwave-door-window-sensor.groovy | 91 +- .../zwave-dual-switch.groovy | 26 +- .../zwave-fan-controller.groovy | 65 +- .../zwave-garage-door-opener.groovy | 10 +- .../zwave-lock-without-codes.groovy | 131 +- .../zwave-lock.src/zwave-lock.groovy | 97 +- .../zwave-metering-dimmer.groovy | 86 +- .../zwave-metering-switch-secure.groovy | 4 +- .../zwave-metering-switch.groovy | 53 +- .../zwave-motion-light-sensor.groovy | 37 +- .../zwave-motion-light.groovy | 48 +- .../zwave-motion-sensor.groovy | 141 +- .../zwave-motion-temp-light-sensor.groovy | 8 +- .../zwave-mouse-trap.groovy | 4 +- .../zwave-multi-button.groovy | 79 +- .../zwave-multi-metering-switch.groovy | 22 +- .../zwave-plus-door-window-sensor.groovy | 6 +- .../zwave-plus-motion-temp-sensor.groovy | 8 +- .../zwave-radiator-thermostat.groovy | 51 +- .../zwave-range-extender.groovy | 14 +- .../zwave-relay.src/zwave-relay.groovy | 4 +- .../zwave-sensor.src/zwave-sensor.groovy | 8 + .../zwave-siren.src/i18n/messages.properties | 306 ++++ .../zwave-siren.src/zwave-siren.groovy | 96 +- .../zwave-smoke-alarm.groovy | 32 +- .../zwave-sound-sensor.groovy | 2 +- .../zwave-switch-battery.groovy | 10 +- .../zwave-switch-generic.groovy | 70 +- .../zwave-switch-secure.groovy | 11 +- .../zwave-switch.src/zwave-switch.groovy | 8 +- .../zwave-thermostat.groovy | 10 +- .../zwave-water-sensor.groovy | 58 +- .../zwave-water-temp-humidity-sensor.groovy | 230 +++ .../zwave-water-temp-light-sensor.groovy | 2 +- .../zwave-water-valve.groovy | 10 +- .../zwave-window-shade.groovy | 51 +- .../stelpro-ki-thermostat.groovy | 38 +- .../stelpro-ki-zigbee-thermostat.groovy | 15 +- .../stelpro-maestro-thermostat.groovy | 17 +- .../zen-thermostat.src/zen-thermostat.groovy | 2 +- .../curb-energy-monitor.groovy | 4 +- .../button-controller.groovy | 4 + .../ecobee-connect.src/ecobee-connect.groovy | 4 +- .../ecobee-connect.src/i18n/ar-AE.properties | 2 +- .../ecobee-connect.src/i18n/bg-BG.properties | 2 +- .../ecobee-connect.src/i18n/ca-ES.properties | 2 +- .../ecobee-connect.src/i18n/cs-CZ.properties | 2 +- .../ecobee-connect.src/i18n/da-DK.properties | 2 +- .../ecobee-connect.src/i18n/de-DE.properties | 2 +- .../ecobee-connect.src/i18n/el-GR.properties | 2 +- .../ecobee-connect.src/i18n/en-GB.properties | 2 +- .../ecobee-connect.src/i18n/es-ES.properties | 2 +- .../ecobee-connect.src/i18n/es-MX.properties | 2 +- .../ecobee-connect.src/i18n/es-US.properties | 2 +- .../ecobee-connect.src/i18n/et-EE.properties | 2 +- .../ecobee-connect.src/i18n/fi-FI.properties | 2 +- .../ecobee-connect.src/i18n/fr-CA.properties | 2 +- .../ecobee-connect.src/i18n/fr-FR.properties | 2 +- .../ecobee-connect.src/i18n/hr-HR.properties | 2 +- .../ecobee-connect.src/i18n/hu-HU.properties | 2 +- .../ecobee-connect.src/i18n/it-IT.properties | 2 +- .../ecobee-connect.src/i18n/ko-KR.properties | 2 +- .../ecobee-connect.src/i18n/nl-NL.properties | 2 +- .../ecobee-connect.src/i18n/no-NO.properties | 2 +- .../ecobee-connect.src/i18n/pl-PL.properties | 2 +- .../ecobee-connect.src/i18n/pt-BR.properties | 2 +- .../ecobee-connect.src/i18n/pt-PT.properties | 2 +- .../ecobee-connect.src/i18n/ro-RO.properties | 2 +- .../ecobee-connect.src/i18n/ru-RU.properties | 2 +- .../ecobee-connect.src/i18n/sk-SK.properties | 2 +- .../ecobee-connect.src/i18n/sl-SI.properties | 2 +- .../ecobee-connect.src/i18n/sq-AL.properties | 2 +- .../ecobee-connect.src/i18n/sr-RS.properties | 2 +- .../ecobee-connect.src/i18n/sv-SE.properties | 2 +- .../ecobee-connect.src/i18n/th-TH.properties | 2 +- .../ecobee-connect.src/i18n/tr-TR.properties | 2 +- .../ecobee-connect.src/i18n/zh-CN.properties | 2 +- smartapps/smartthings/ifttt.src/ifttt.groovy | 20 +- .../lifx-connect.src/i18n/ar-AE.properties | 27 - .../lifx-connect.src/i18n/bg-BG.properties | 27 - .../lifx-connect.src/i18n/ca-ES.properties | 11 - .../lifx-connect.src/i18n/cs-CZ.properties | 27 - .../lifx-connect.src/i18n/da-DK.properties | 27 - .../lifx-connect.src/i18n/de-DE.properties | 27 - .../lifx-connect.src/i18n/el-GR.properties | 27 - .../lifx-connect.src/i18n/en-GB.properties | 27 - .../lifx-connect.src/i18n/en-US.properties | 11 - .../lifx-connect.src/i18n/es-ES.properties | 27 - .../lifx-connect.src/i18n/es-MX.properties | 11 - .../lifx-connect.src/i18n/es-US.properties | 16 - .../lifx-connect.src/i18n/et-EE.properties | 27 - .../lifx-connect.src/i18n/fi-FI.properties | 27 - .../lifx-connect.src/i18n/fr-CA.properties | 27 - .../lifx-connect.src/i18n/fr-FR.properties | 27 - .../lifx-connect.src/i18n/hr-HR.properties | 27 - .../lifx-connect.src/i18n/hu-HU.properties | 27 - .../lifx-connect.src/i18n/it-IT.properties | 27 - .../lifx-connect.src/i18n/ko-KR.properties | 27 - .../lifx-connect.src/i18n/nl-NL.properties | 27 - .../lifx-connect.src/i18n/no-NO.properties | 27 - .../lifx-connect.src/i18n/pl-PL.properties | 27 - .../lifx-connect.src/i18n/pt-BR.properties | 27 - .../lifx-connect.src/i18n/pt-PT.properties | 27 - .../lifx-connect.src/i18n/ro-RO.properties | 27 - .../lifx-connect.src/i18n/ru-RU.properties | 27 - .../lifx-connect.src/i18n/sk-SK.properties | 27 - .../lifx-connect.src/i18n/sl-SI.properties | 27 - .../lifx-connect.src/i18n/sq-AL.properties | 27 - .../lifx-connect.src/i18n/sr-RS.properties | 27 - .../lifx-connect.src/i18n/sv-SE.properties | 27 - .../lifx-connect.src/i18n/th-TH.properties | 27 - .../lifx-connect.src/i18n/tr-TR.properties | 27 - .../lifx-connect.src/i18n/zh-CN.properties | 21 - .../lifx-connect.src/lifx-connect.groovy | 540 ------ 356 files changed, 17044 insertions(+), 6287 deletions(-) create mode 100755 .githooks/pre-commit create mode 100644 devicetypes/erocm123/inovelli-2-channel-smart-plug-mcd.src/inovelli-2-channel-smart-plug-mcd.groovy create mode 100644 devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy create mode 100644 devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy create mode 100644 devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy create mode 100644 devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy create mode 100644 devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy create mode 100644 devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy create mode 100644 devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy create mode 100644 devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy create mode 100644 devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy create mode 100644 devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy create mode 100644 devicetypes/qubino/qubino-temperature-sensor.src/qubino-temperature-sensor.groovy create mode 100644 devicetypes/rooms-beautiful/rooms-beautiful-curtain.src/rooms-beautiful-curtain.groovy mode change 100644 => 100755 devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy create mode 100755 devicetypes/smartthings/Orvibo-Contact-Sensor.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/aeotec-doorbell-siren-6.src/aeotec-doorbell-siren-6.groovy create mode 100644 devicetypes/smartthings/aeotec-doorbell-siren-child.src/aeotec-doorbell-siren-child.groovy create mode 100644 devicetypes/smartthings/child-color-control.src/child-color-control.groovy create mode 100644 devicetypes/smartthings/child-contact-sensor.src/child-contact-sensor.groovy create mode 100644 devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy create mode 100644 devicetypes/smartthings/child-switch-multilevel.src/child-switch-multilevel.groovy create mode 100644 devicetypes/smartthings/child-venetian-blind.src/child-venetian-blind.groovy create mode 100644 devicetypes/smartthings/dawon-zwave-wall-smart-switch.src/dawon-zwave-wall-smart-switch.groovy create mode 100644 devicetypes/smartthings/ecosmart-4button-remote.src/ecosmart-4button-remote.groovy create mode 100644 devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy delete mode 100644 devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy delete mode 100644 devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy create mode 100755 devicetypes/smartthings/orvibo-Moisture-Sensor.src/i18n/messages.properties create mode 100755 devicetypes/smartthings/orvibo-gas-detector.src/i18n/messages.properties create mode 100755 devicetypes/smartthings/ozom-smart-siren.src/i18n/messages.properties mode change 100644 => 100755 devicetypes/smartthings/smartsense-button.src/i18n/messages.properties mode change 100644 => 100755 devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy create mode 100644 devicetypes/smartthings/smartsense-garage-door-multi.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/smartsense-garage-door-sensor-button.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/smartsense-multi.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/smartsense-open-closed-sensor.src/i18n/messages.properties create mode 100755 devicetypes/smartthings/smartsense-temp-humidity-sensor.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/smartsense-virtual-open-closed.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.apparentTemperature.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.astronomicalData.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.precipitation.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.smartWeather.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.ultravioletDescription.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherAlert.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherForecast.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherSummary.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windDirection.json create mode 100644 devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windSpeed.json create mode 100644 devicetypes/smartthings/tyco-door-window-sensor.src/i18n/messages.properties mode change 100644 => 100755 devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy create mode 100755 devicetypes/smartthings/zigbee-co-sensor.src/i18n/messages.properties mode change 100644 => 100755 devicetypes/smartthings/zigbee-co-sensor.src/zigbee-co-sensor.groovy mode change 100755 => 100644 devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy create mode 100755 devicetypes/smartthings/zigbee-motion-detector.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/i18n/messages.properties create mode 100755 devicetypes/smartthings/zigbee-multi-button.src/i18n/messages.properties mode change 100755 => 100644 devicetypes/smartthings/zigbee-multi-switch.src/i18n/messages.properties mode change 100755 => 100644 devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy create mode 100755 devicetypes/smartthings/zigbee-non-holdable-button.src/i18n/messages.properties create mode 100755 devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy create mode 100644 devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties create mode 100755 devicetypes/smartthings/zigbee-smoke-sensor.src/i18n/messages.properties mode change 100644 => 100755 devicetypes/smartthings/zigbee-smoke-sensor.src/zigbee-smoke-sensor.groovy mode change 100755 => 100644 devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy create mode 100644 devicetypes/smartthings/zwave-basic-window-shade.src/zwave-basic-window-shade.groovy create mode 100644 devicetypes/smartthings/zwave-door-temp-sensor.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/zwave-siren.src/i18n/messages.properties create mode 100644 devicetypes/smartthings/zwave-water-temp-humidity-sensor.src/zwave-water-temp-humidity-sensor.groovy delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/ar-AE.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/bg-BG.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/ca-ES.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/cs-CZ.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/da-DK.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/de-DE.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/el-GR.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/en-GB.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/en-US.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/es-ES.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/es-MX.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/es-US.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/et-EE.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/fi-FI.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/fr-CA.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/fr-FR.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/hr-HR.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/hu-HU.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/it-IT.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/ko-KR.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/nl-NL.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/no-NO.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/pl-PL.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/pt-BR.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/pt-PT.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/ro-RO.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/ru-RU.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/sk-SK.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/sl-SI.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/sq-AL.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/sr-RS.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/sv-SE.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/th-TH.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/tr-TR.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/i18n/zh-CN.properties delete mode 100644 smartapps/smartthings/lifx-connect.src/lifx-connect.groovy diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000000..eb55586debf --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,22 @@ +#!/bin/bash + +ERROR_COUNT=0 +while IFS= read -r DTH; do + echo "Verifying $DTH" + ERRORS=$(groovyc $DTH 2>&1 | grep ".groovy:") + # echo $ERRORS + IMPORTANT_ERRORS=$(echo $ERRORS | grep -v "unable") + if [[ ${#IMPORTANT_ERRORS} -eq 0 ]]; then + echo "No disqualifying compilation errors found" + else + echo "$DTH failed to compile, run groovyc on your source file for the full error: $ERRORS" + ERROR_COUNT=$((ERROR_COUNT + 1)) + fi + echo "=======================================================================" +done < <(git diff --cached --name-only | grep .*.groovy) + +if [[ $ERROR_COUNT -gt 0 ]]; then + echo "rejected" && exit 1 +else + exit 0 +fi \ No newline at end of file diff --git a/build.gradle b/build.gradle index 923ca425e6a..200bc83c86c 100644 --- a/build.gradle +++ b/build.gradle @@ -138,3 +138,17 @@ slackSendMessage { text: messageText ) } + +task configure(type: Exec) { + description "Configures automatic spaces->tabs conversion on merge and a commit hook to detect syntax errors" + File attributeFile = new File("${projectDir}/.git/info/attributes") + attributeFile.write("*.groovy filter=tabspace\n") + commandLine "git", "config", "filter.tabspace.clean", "unexpand -t 2" + commandLine "git", "config", "core.hooksPath", ".githooks" +} + +task unconfigure(type: Exec) { + description "Undoes configuration put in place by configure" + commandLine "git", "config", "--unset-all", "filter.tabspace.clean" + commandLine "git", "config", "core.hooksPath", "${projectDir}/.git/hooks" +} diff --git a/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy b/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy index f73c65af0c8..e9913b1128f 100644 --- a/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy +++ b/devicetypes/axis/axis-gear-st.src/axis-gear-st.groovy @@ -1,7 +1,7 @@ import groovy.json.JsonOutput metadata { - definition (name: "AXIS Gear ST", namespace: "axis", author: "AXIS Labs", ocfDeviceType: "oic.d.blind", vid: "generic-shade-2") { + definition (name: "AXIS Gear ST", namespace: "axis", author: "AXIS Labs", ocfDeviceType: "oic.d.blind", vid: "generic-shade-3") { capability "Window Shade" capability "Window Shade Preset" capability "Switch Level" @@ -22,9 +22,9 @@ metadata { command "stop" command "getversion" - fingerprint profileID: "0104", manufacturer: "AXIS", model: "Gear", deviceJoinName: "AXIS Gear" - fingerprint profileId: "0104", deviceId: "0202", inClusters: "0000, 0003, 0006, 0008, 0102, 0020, 0001", outClusters: "0019", manufacturer: "AXIS", model: "Gear", deviceJoinName: "AXIS Gear" - fingerprint endpointID: "01, C4", profileId: "0104, C25D", deviceId: "0202", inClusters: "0000, 0003, 0006, 0008, 0102, 0020, 0001", outClusters: "0019", manufacturer: "AXIS", model: "Gear", deviceJoinName: "AXIS Gear" + fingerprint profileID: "0104", manufacturer: "AXIS", model: "Gear", deviceJoinName: "AXIS Window Treatment" //AXIS Gear + fingerprint profileId: "0104", deviceId: "0202", inClusters: "0000, 0003, 0006, 0008, 0102, 0020, 0001", outClusters: "0019", manufacturer: "AXIS", model: "Gear", deviceJoinName: "AXIS Window Treatment" //AXIS Gear + fingerprint endpointID: "01, C4", profileId: "0104, C25D", deviceId: "0202", inClusters: "0000, 0003, 0006, 0008, 0102, 0020, 0001", outClusters: "0019", manufacturer: "AXIS", model: "Gear", deviceJoinName: "AXIS Window Treatment" //AXIS Gear //ClusterIDs: 0000 - Basic; 0006 - On/Off; 0008 - Level Control; 0102 - Window Covering; //Updated 2017-06-21 @@ -34,6 +34,7 @@ metadata { //Updated 2018-11-01 - added in configure reporting for refresh button, close when press on partial shade icon, update handler to parse between 0-254 as a percentage //Updated 2019-06-03 - modified to use Window Covering Cluster Commands and versioning tile and backwards compatibility (firmware and app), fingerprinting enabled //Updated 2019-08-09 - minor changes and improvements, onoff state reporting fixed + //Updated 2019-11-11 - minor changes } tiles(scale: 2) { @@ -83,7 +84,7 @@ metadata { state "default", label: "Preset", action:"presetPosition", icon:"st.Home.home2" } preferences { - input "preset", "number", title: "Preset percentage (1-100) [Default - 50%]", defaultValue: 50, required: false, displayDuringSetup: true, range:"(1..100)" + input "preset", "number", title: "Preset position", description: "Set the window shade preset position", defaultValue: 50, required: false, displayDuringSetup: true, range:"1..100" } main(["main"]) @@ -415,4 +416,4 @@ private Map parseReportAttributeMessage(String description) { log.debug "parseReportAttributeMessage() --- ignoring attribute" } return resultMap -} \ No newline at end of file +} diff --git a/devicetypes/drzwave/ezmultipli.src/ezmultipli.groovy b/devicetypes/drzwave/ezmultipli.src/ezmultipli.groovy index 9fb79332277..3102eea2704 100644 --- a/devicetypes/drzwave/ezmultipli.src/ezmultipli.groovy +++ b/devicetypes/drzwave/ezmultipli.src/ezmultipli.groovy @@ -18,7 +18,7 @@ metadata { capability "Refresh" capability "Health Check" - fingerprint mfr: "001E", prod: "0004", model: "0001" + fingerprint mfr: "001E", prod: "0004", model: "0001", deviceJoinName: "EZmultiPli Multipurpose Sensor" } simulator { @@ -135,6 +135,8 @@ def setupHealthCheck() { def installed() { sendEvent(name: "motion", value: "inactive", displayed: false) state.colorReceived = [red: null, green: null, blue: null] + state.setColor = [red: null, green: null, blue: null] + state.colorQueryFailures = 0 setupHealthCheck() } @@ -247,15 +249,30 @@ def zwaveEvent(switchcolorv3.SwitchColorReport cmd) { result << createEvent(name: "color", value: hexColor) // Send the color as hue and saturation def hsv = rgbToHSV(*colors) - result << createEvent(name: "hue", value: hsv.hue) - result << createEvent(name: "saturation", value: hsv.saturation) - // Reset the values - RGB_NAMES.collect { state.colorReceived[it] = null} + if (state.setColor.red == state.colorReceived.red && state.setColor.green == state.colorReceived.green && state.setColor.blue == state.colorReceived.blue) { + unschedule() + result << createEvent(name: "hue", value: hsv.hue) + result << createEvent(name: "saturation", value: hsv.saturation) + state.colorQueryFailures = 0 + } else { + if (++state.colorQueryFailures >= 6) { + sendHubCommand(commands([ + zwave.switchColorV3.switchColorSet(red: state.setColor.red, green: state.setColor.green, blue: state.setColor.blue), + queryAllColors() + ])) + } else { + runIn(2, "sendColorQueryCommands", [overwrite: true]) + } + } } result } +private sendColorQueryCommands() { + sendHubCommand(commands(queryAllColors())) +} + def zwaveEvent(physicalgraph.zwave.Command cmd) { // Handles all Z-Wave commands we aren't interested in log.debug "Unhandled $cmd" @@ -324,6 +341,7 @@ def setColor(value) { return } + state.setColor = [red: myred, green: mygreen, blue: myblue] cmds << zwave.switchColorV3.switchColorSet(red: myred, green: mygreen, blue: myblue) cmds << zwave.basicV1.basicGet() @@ -391,7 +409,7 @@ private crcEncap(physicalgraph.zwave.Command cmd) { private command(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")) { + } else if (zwaveInfo?.cc?.contains("56")) { crcEncap(cmd) } else { cmd.format() diff --git a/devicetypes/erocm123/inovelli-2-channel-smart-plug-mcd.src/inovelli-2-channel-smart-plug-mcd.groovy b/devicetypes/erocm123/inovelli-2-channel-smart-plug-mcd.src/inovelli-2-channel-smart-plug-mcd.groovy new file mode 100644 index 00000000000..2d4336e47c5 --- /dev/null +++ b/devicetypes/erocm123/inovelli-2-channel-smart-plug-mcd.src/inovelli-2-channel-smart-plug-mcd.groovy @@ -0,0 +1,303 @@ +/** + * + * Inovelli 2-Channel Smart Plug MCD + * + * Copyright 2020 SmartThings + * + * Original integration: + * github: Eric Maycock (erocm123) + * Date: 2017-04-27 + * Copyright Eric Maycock + * + * Includes all configuration parameters and ease of advanced configuration. + * + * 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: "Inovelli 2-Channel Smart Plug MCD", namespace: "erocm123", author: "Eric Maycock", ocfDeviceType: "oic.d.smartplug", mcdSync: true) { + capability "Actuator" + capability "Sensor" + capability "Switch" + capability "Polling" + capability "Refresh" + capability "Health Check" + + fingerprint manufacturer: "015D", prod: "0221", model: "251C", deviceJoinName: "Show Home Outlet" // Show Home 2-Channel Smart Plug + fingerprint manufacturer: "0312", prod: "0221", model: "251C", deviceJoinName: "Inovelli Outlet" // Inovelli 2-Channel Smart Plug + fingerprint manufacturer: "0312", prod: "B221", model: "251C", deviceJoinName: "Inovelli Outlet" // Inovelli 2-Channel Smart Plug + fingerprint manufacturer: "0312", prod: "0221", model: "611C", deviceJoinName: "Inovelli Outlet" // Inovelli 2-Channel Outdoor Smart Plug + fingerprint manufacturer: "015D", prod: "0221", model: "611C", deviceJoinName: "Inovelli Outlet" // Inovelli 2-Channel Outdoor Smart Plug + fingerprint manufacturer: "015D", prod: "6100", model: "6100", deviceJoinName: "Inovelli Outlet" // Inovelli 2-Channel Outdoor Smart Plug + fingerprint manufacturer: "0312", prod: "6100", model: "6100", deviceJoinName: "Inovelli Outlet" // Inovelli 2-Channel Outdoor Smart Plug + fingerprint manufacturer: "015D", prod: "2500", model: "2500", deviceJoinName: "Inovelli Outlet" // Inovelli 2-Channel Smart Plug w/Scene + } + simulator {} + preferences {} + tiles { + multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + } + } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh" + } + main(["switch"]) + details(["switch", + childDeviceTiles("all"), "refresh" + ]) + } +} + +def parse(String description) { + def result = [] + def cmd = zwave.parse(description) + + if (cmd) { + result += zwaveEvent(cmd) + log.debug "Parsed ${cmd} to ${result.inspect()}" + } else { + log.debug "Non-parsed event: ${description}" + } + + return result +} + +def handleSwitchEndpointEvent(cmd, ep) { + def event + def childDevice = childDevices.find { it.deviceNetworkId == "$device.deviceNetworkId:$ep" } + + childDevice?.sendEvent(name: "switch", value: cmd.value ? "on" : "off") + + if (cmd.value) { + event = [createEvent([name: "switch", value: "on"])] + } else { + def allOff = true + + childDevices.each { n -> + if (n.currentState("switch")?.value != "off") + allOff = false + } + + if (allOff) { + event = [createEvent([name: "switch", value: "off"])] + } else { + event = [createEvent([name: "switch", value: "on"])] + } + } + + return event +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + log.debug "BasicReport ${cmd} - outlet ${ep}" + + if (ep) { + return handleSwitchEndpointEvent(cmd, ep) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + log.debug "BasicSet ${cmd}" + def result = createEvent(name: "switch", value: cmd.value ? "on" : "off") + def cmds = [] + + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1) + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + + return [result, response(commands(cmds))] +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) { + log.debug "SwitchBinaryReport ${cmd} - outlet ${ep}" + + if (ep) { + return handleSwitchEndpointEvent(cmd, ep) + } else { + def result = createEvent(name: "switch", value: cmd.value ? "on" : "off") + def cmds = [] + + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1) + cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + + return [result, response(commands(cmds))] + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + log.debug "MultiChannelCmdEncap ${cmd}" + def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) + + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) + } +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + // This will capture any commands not handled by other instances of zwaveEvent + // and is recommended for development so you can see every command the device sends + log.debug "Unhandled Event: ${cmd}" +} + +def on() { + log.debug "on()" + + commands([ + zwave.switchAllV1.switchAllOn(), + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + ]) +} + +def off() { + log.debug "off()" + + commands([ + zwave.switchAllV1.switchAllOff(), + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2) + ]) +} + +void childOn(String dni) { + log.debug "childOn($dni)" + def cmds = [] + + cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(dni)))) + cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni)))) + + sendHubCommand(cmds, 1000) +} + +void childOff(String dni) { + log.debug "childOff($dni)" + def cmds = [] + + cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(dni)))) + cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni)))) + + sendHubCommand(cmds, 1000) +} + +void childRefresh(String dni) { + log.debug "childRefresh($dni)" + def cmds = [] + + cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni)))) + + sendHubCommand(cmds, 1000) +} + +def poll() { + log.debug "poll()" + + refresh() +} + +def refresh() { + log.debug "refresh()" + + commands([ + encap(zwave.switchBinaryV1.switchBinaryGet(), 1), + encap(zwave.switchBinaryV1.switchBinaryGet(), 2), + ]) +} + +def ping() { + log.debug "ping()" + + refresh() +} + +def getCheckInterval() { + 2 * 15 * 60 + 2 * 60 +} + +def installed() { + log.debug "installed()" + + sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + createChildDevices() + response(refresh()) +} + +def updated() { + log.debug "updated()" + + if (!childDevices) { + createChildDevices() + } else if (device.label != state.oldLabel) { + childDevices.each { + it.setLabel("${device.displayName} Outlet ${channelNumber(it.deviceNetworkId)}") + } + state.oldLabel = device.label + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + log.debug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'" +} + +private encap(cmd, endpoint) { + if (endpoint) { + zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } else { + cmd + } +} + +private command(physicalgraph.zwave.Command cmd) { + if (state.sec) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } +} + +private commands(commands, delay = 1000) { + delayBetween(commands.collect { + command(it) + }, delay) +} + +private channelNumber(String dni) { + dni.split(":")[-1] as Integer +} + +private void createChildDevices() { + state.oldLabel = device.label + + for (i in 1..2) { + def newDevice = addChildDevice("smartthings", "Child Switch Health", + "${device.deviceNetworkId}:${i}", + device.hubId, + [completedSetup: true, + label: "${device.displayName} Outlet ${i}", + isComponent: true, + componentName: "outlet$i", + componentLabel: "Outlet $i" + ]) + + newDevice.sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } +} diff --git a/devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy b/devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy index 1ee57352507..f20d7636a7e 100644 --- a/devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy +++ b/devicetypes/erocm123/inovelli-2-channel-smart-plug.src/inovelli-2-channel-smart-plug.groovy @@ -27,14 +27,7 @@ metadata { capability "Refresh" capability "Health Check" - fingerprint manufacturer: "015D", prod: "0221", model: "251C", deviceJoinName: "Show Home 2-Channel Smart Plug" - fingerprint manufacturer: "0312", prod: "0221", model: "251C", deviceJoinName: "Inovelli 2-Channel Smart Plug" - fingerprint manufacturer: "0312", prod: "B221", model: "251C", deviceJoinName: "Inovelli 2-Channel Smart Plug" - fingerprint manufacturer: "0312", prod: "0221", model: "611C", deviceJoinName: "Inovelli 2-Channel Outdoor Smart Plug" - fingerprint manufacturer: "015D", prod: "0221", model: "611C", deviceJoinName: "Inovelli 2-Channel Outdoor Smart Plug" - fingerprint manufacturer: "015D", prod: "6100", model: "6100", deviceJoinName: "Inovelli 2-Channel Outdoor Smart Plug" - fingerprint manufacturer: "0312", prod: "6100", model: "6100", deviceJoinName: "Inovelli 2-Channel Outdoor Smart Plug" - fingerprint manufacturer: "015D", prod: "2500", model: "2500", deviceJoinName: "Inovelli 2-Channel Smart Plug w/Scene" + // Fingerprints moved to "Inovelli 2-Channel Smart Plug MCD" for modern MCD experience. } simulator {} preferences {} @@ -83,7 +76,7 @@ def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) def allOff = true childDevices.each { n -> - if (n.currentState("switch").value != "off") allOff = false + if (n.currentState("switch")?.value != "off") allOff = false } if (allOff) { event = [createEvent([name: "switch", value: "off"])] @@ -116,7 +109,7 @@ def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cm def allOff = true childDevices.each { n-> - if (n.currentState("switch").value != "off") allOff = false + if (n.currentState("switch")?.value != "off") allOff = false } if (allOff) { event = [createEvent([name: "switch", value: "off"])] @@ -134,6 +127,14 @@ def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cm } } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } logging("MultiChannelCmdEncap ${cmd}", 2) def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) if (encapsulatedCommand) { @@ -208,7 +209,9 @@ def ping() { def installed() { logging("installed()", 1) command(zwave.manufacturerSpecificV1.manufacturerSpecificGet()) - createChildDevices() + if (!childDevices) { // Clicking "Update" from the Graph IDE calls installed(), so protect against trying to recreate children. + createChildDevices() + } } def updated() { logging("updated()", 1) @@ -225,6 +228,26 @@ def updated() { } sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) sendEvent(name: "needUpdate", value: device.currentValue("needUpdate"), displayed: false, isStateChange: true) + + migrate() +} +def migrate() { + log.info "Migrating to MCD DTH" + + childDevices.each { + def i = it.deviceNetworkId[-1] + + log.info "Migrating child ${i} from ${it.componentName} to outlet${i}" + + it.save([deviceNetworkId: "${device.deviceNetworkId}:${i}", + label: "${device.displayName} Outlet ${i}", + isComponent: true, + componentName: "outlet$i", + componentLabel: "Outlet $i"]) + it.setDeviceType("smartthings", "Child Switch Health") + } + + setDeviceType("erocm123", "Inovelli 2-Channel Smart Plug MCD") } def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { logging("${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'", 2) diff --git a/devicetypes/fibargroup/fibaro-co-sensor-zw5.src/fibaro-co-sensor-zw5.groovy b/devicetypes/fibargroup/fibaro-co-sensor-zw5.src/fibaro-co-sensor-zw5.groovy index 94b62ca5e89..2c35cb117c8 100644 --- a/devicetypes/fibargroup/fibaro-co-sensor-zw5.src/fibaro-co-sensor-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-co-sensor-zw5.src/fibaro-co-sensor-zw5.groovy @@ -14,9 +14,9 @@ metadata { attribute "coLevel", "number" - fingerprint mfr: "010F", prod: "1201", model: "1000" - fingerprint mfr: "010F", prod: "1201", model: "1001" - fingerprint mfr: "010F", prod: "1201" + fingerprint mfr: "010F", prod: "1201", model: "1000", deviceJoinName: "Fibaro Carbon Monoxide Sensor" + fingerprint mfr: "010F", prod: "1201", model: "1001", deviceJoinName: "Fibaro Carbon Monoxide Sensor" + fingerprint mfr: "010F", prod: "1201", deviceJoinName: "Fibaro Carbon Monoxide Sensor" } tiles (scale: 2) { @@ -67,17 +67,7 @@ metadata { } preferences { - - input ( - title: "Fibaro CO Sensor ZW5 manual", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2017/07/co_icon.png", - url: "http://manuals.fibaro.com/content/manuals/en/FGCD-001/FGCD-001-EN-T-v1.1.pdf", - type: "href", - element: "href" - ) - - parameterMap().findAll{(it.num as Integer) != 54}.each { + parameterMap().each { input ( title: "${it.num}. ${it.title}", description: it.descr, @@ -85,10 +75,12 @@ metadata { element: "paragraph" ) + def defVal = it.def as Integer + def descrDefVal = it.options ? it.options.get(defVal) : defVal input ( name: it.key, title: null, - description: "Default: $it.def" , + description: "$descrDefVal", type: it.type, options: it.options, range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, @@ -102,7 +94,7 @@ metadata { } def installed() { - sendEvent(name: "checkInterval", value: 86520, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: 12 * 60 * 60 + 8 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } def updated() { @@ -374,7 +366,7 @@ private crcEncap(physicalgraph.zwave.Command cmd) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { logging("${device.displayName} - no encapsulation supported for command: $cmd","info") diff --git a/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy b/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy index 90d15258005..dfed370f98a 100644 --- a/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-dimmer-2-zw5.src/fibaro-dimmer-2-zw5.groovy @@ -16,10 +16,11 @@ metadata { attribute "errorMode", "string" attribute "scene", "string" + attribute "multiStatus", "string" - fingerprint mfr: "010F", prod: "0102", model: "2000" - fingerprint mfr: "010F", prod: "0102", model: "1000" - fingerprint mfr: "010F", prod: "0102", model: "3000" + fingerprint mfr: "010F", prod: "0102", model: "2000", deviceJoinName: "Fibaro Dimmer Switch" + fingerprint mfr: "010F", prod: "0102", model: "1000", deviceJoinName: "Fibaro Dimmer Switch" + fingerprint mfr: "010F", prod: "0102", model: "3000", deviceJoinName: "Fibaro Dimmer Switch" } tiles (scale: 2) { @@ -31,7 +32,7 @@ metadata { attributeState "turningOff", label:'Turning Off', action:"on", icon:"https://s3-eu-west-1.amazonaws.com/fibaro-smartthings/dimmer/dimmer50.png", backgroundColor:"#ffffff", nextState:"turningOn" } tileAttribute("device.multiStatus", key:"SECONDARY_CONTROL") { - attributeState("combinedMeter", label:'${currentValue}') + attributeState("multiStatus", label:'${currentValue}') } tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action:"switch level.setLevel" @@ -67,15 +68,6 @@ metadata { } preferences { - input ( - title: "Fibaro Dimmer 2 ZW5 manual", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2017/02/d2_icon.png", - url: "http://manuals.fibaro.com/content/manuals/en/FGD-212/FGD-212-EN-T-v1.3.pdf", - type: "href", - element: "href" - ) - parameterMap().each { input ( title: "${it.num}. ${it.title}", @@ -389,6 +381,24 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { } } +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + def result = null + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + def encapsulatedCommand = cmd.encapsulatedCommand(cmdVersions()) + log.debug "Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}" + if (encapsulatedCommand) { + result = zwaveEvent(encapsulatedCommand) + } + result +} + def zwaveEvent(physicalgraph.zwave.Command cmd) { // Handles all Z-Wave commands we aren't interested in log.debug "Unhandled: ${cmd.toString()}" @@ -427,7 +437,7 @@ private encap(Map encapMap) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { logging("${device.displayName} - no encapsulation supported for command: $cmd","info") diff --git a/devicetypes/fibargroup/fibaro-door-window-sensor-2.src/fibaro-door-window-sensor-2.groovy b/devicetypes/fibargroup/fibaro-door-window-sensor-2.src/fibaro-door-window-sensor-2.groovy index abdfe05d609..d7d0ce0dfee 100644 --- a/devicetypes/fibargroup/fibaro-door-window-sensor-2.src/fibaro-door-window-sensor-2.groovy +++ b/devicetypes/fibargroup/fibaro-door-window-sensor-2.src/fibaro-door-window-sensor-2.groovy @@ -16,15 +16,15 @@ metadata { capability "Contact Sensor" capability "Tamper Alert" capability "Temperature Measurement" + capability "Temperature Alarm" capability "Configuration" capability "Battery" capability "Sensor" capability "Health Check" - - attribute "temperatureAlarm", "string" + attribute "multiStatus", "string" - fingerprint mfr: "010F", prod: "0702" + fingerprint mfr: "010F", prod: "0702", deviceJoinName: "Fibaro Open/Closed Sensor" } tiles (scale: 2) { @@ -62,26 +62,17 @@ metadata { standardTile("temperatureAlarm", "device.temperatureAlarm", inactiveLabel: false, width: 2, height: 2, decoration: "flat") { state "default", label: "No temp. alarm", backgroundColor:"#ffffff" - state "clear", label:'', backgroundColor:"#ffffff", icon: "st.alarm.temperature.normal" - state "underheat", label:'underheat', backgroundColor:"#1e9cbb", icon: "st.alarm.temperature.freeze" - state "overheat", label:'overheat', backgroundColor:"#d04e00", icon: "st.alarm.temperature.overheat" + state "cleared", label:'', backgroundColor:"#ffffff", icon: "st.alarm.temperature.normal" + state "freeze", label:'freeze', backgroundColor:"#1e9cbb", icon: "st.alarm.temperature.freeze" + state "heat", label:'heat', backgroundColor:"#d04e00", icon: "st.alarm.temperature.overheat" } main "FGDW" details(["FGDW","tamper","temperature","battery","temperatureAlarm"]) } - + + preferences { - - input ( - title: "Fibaro Door/Window Sensor 2", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2017/05/dws2.jpg", - url: "http://manuals.fibaro.com/content/manuals/en/FGDW-002/FGDW-002-EN-T-v1.0.pdf", - type: "href", - element: "href" - ) - input ( title: "Wake up interval", description: "How often should your device automatically sync with the HUB. The lower the value, the shorter the battery life.\n0 or 1-18 (in hours)", @@ -98,18 +89,19 @@ metadata { required: false ) - parameterMap().findAll{(it.num as Integer) != 54}.each { + parameterMap().each { input ( title: "${it.num}. ${it.title}", description: it.descr, type: "paragraph", element: "paragraph" ) - + def defVal = it.def as Integer + def descrDefVal = it.options ? it.options.get(defVal) : defVal input ( name: it.key, title: null, - description: "Default: $it.def" , + description: "$descrDefVal", type: it.type, options: it.options, range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, @@ -127,6 +119,7 @@ def installed() { // Initial states for OCF compatibility sendEvent(name: "tamper", value: "clear", displayed: false) sendEvent(name: "contact", value: "open", displayed: false) + sendEvent(name: "temperatureAlarm", value: "cleared", displayed: false) sendEvent(name: "checkInterval", value: 21600 * 4 + 120, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } @@ -139,12 +132,26 @@ def updated() { } logging("${device.displayName} - Executing updated()","debug") - if ( settings.temperatureHigh as Integer == 0 && settings.temperatureLow as Integer == 0 ) { - sendEvent(name: "temperatureAlarm", value: null, displayed: false) - } else if ( settings.temperatureHigh != null || settings.temperatureHigh != null ) { - sendEvent(name: "temperatureAlarm", value: "clear", displayed: false) + def tempAlarmMap = ["clear": "cleared", "overheat": "heat", "underheat": "freeze"] + // Convert old device specific temperatureAlarm event to standard Temperature Alarm capability event + def temperatureAlarmCurrentValue = device.currentValue("temperatureAlarm") + if (tempAlarmMap.containsKey(temperatureAlarmCurrentValue)) { + sendEvent(name: "temperatureAlarm", value: tempAlarmMap[temperatureAlarmCurrentValue], displayed: true) } - + + def currentTemperature = device.currentValue("temperature") + def alarmCleared = device.currentValue("temperatureAlarm") == "cleared" + def alarmFreeze = device.currentValue("temperatureAlarm") == "freeze" + def alarmHeat = device.currentValue("temperatureAlarm") == "heat" + def temperatureHigh = (settings.temperatureHigh ? new BigDecimal(settings.temperatureHigh) * 0.1 : null) + def temperatureLow = (settings.temperatureLow ? new BigDecimal(settings.temperatureLow) * 0.1 : null) + if (!alarmCleared) { + if ((temperatureHigh != null && (currentTemperature < temperatureHigh) && !alarmFreeze) || + (temperatureLow != null && (currentTemperature > temperatureLow) && !alarmHeat)) { + sendEvent(name: "temperatureAlarm", value: "cleared") + } + } + syncStart() state.lastUpdated = now() } @@ -318,15 +325,15 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) { map.name = "temperatureAlarm" switch (cmd.zwaveAlarmEvent) { case 0: - map.value = "clear" + map.value = "cleared" map.descriptionText = "Temperature alert cleared" break case 2: - map.value = "overheat" + map.value = "heat" map.descriptionText = "Temperature alert: overheating detected" break case 6: - map.value = "underheat" + map.value = "freeze" map.descriptionText = "Temperature alert: underheating detected" break } @@ -430,7 +437,7 @@ private crcEncap(physicalgraph.zwave.Command cmd) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { logging("${device.displayName} - no encapsulation supported for command: $cmd","debug") diff --git a/devicetypes/fibargroup/fibaro-door-window-sensor-zw5-with-temperature.src/fibaro-door-window-sensor-zw5-with-temperature.groovy b/devicetypes/fibargroup/fibaro-door-window-sensor-zw5-with-temperature.src/fibaro-door-window-sensor-zw5-with-temperature.groovy index 437096a5f84..2f650ea90ee 100644 --- a/devicetypes/fibargroup/fibaro-door-window-sensor-zw5-with-temperature.src/fibaro-door-window-sensor-zw5-with-temperature.groovy +++ b/devicetypes/fibargroup/fibaro-door-window-sensor-zw5-with-temperature.src/fibaro-door-window-sensor-zw5-with-temperature.groovy @@ -23,8 +23,8 @@ metadata { capability "Temperature Measurement" - fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86", outClusters: "" - fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86, 0x84", outClusters: ""//actual NIF + fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86", outClusters: "", deviceJoinName: "Fibaro Open/Closed Sensor" + fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86, 0x84", outClusters: "", deviceJoinName: "Fibaro Open/Closed Sensor"//actual NIF } simulator { diff --git a/devicetypes/fibargroup/fibaro-door-window-sensor-zw5.src/fibaro-door-window-sensor-zw5.groovy b/devicetypes/fibargroup/fibaro-door-window-sensor-zw5.src/fibaro-door-window-sensor-zw5.groovy index f7534a7b56e..cfbd776b0d4 100644 --- a/devicetypes/fibargroup/fibaro-door-window-sensor-zw5.src/fibaro-door-window-sensor-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-door-window-sensor-zw5.src/fibaro-door-window-sensor-zw5.groovy @@ -18,11 +18,12 @@ metadata { capability "Battery" capability "Contact Sensor" capability "Sensor" - capability "Configuration" - capability "Tamper Alert" + capability "Configuration" + capability "Tamper Alert" capability "Health Check" - fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x86, 0x84", outClusters: "" + fingerprint mfr: "010F", prod: "0700", deviceJoinName: "Fibaro Open/Closed Sensor" + fingerprint mfr: "010F", prod: "0701", deviceJoinName: "Fibaro Open/Closed Sensor" } simulator { diff --git a/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy b/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy index 0a9b7f63346..01e563ef9b3 100644 --- a/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-double-switch-2-zw5.src/fibaro-double-switch-2-zw5.groovy @@ -13,9 +13,9 @@ metadata { command "reset" - fingerprint mfr: "010F", prod: "0203", model: "2000" - fingerprint mfr: "010F", prod: "0203", model: "1000" - fingerprint mfr: "010F", prod: "0203", model: "3000" + fingerprint mfr: "010F", prod: "0203", model: "2000", deviceJoinName: "Fibaro Switch" + fingerprint mfr: "010F", prod: "0203", model: "1000", deviceJoinName: "Fibaro Switch" + fingerprint mfr: "010F", prod: "0203", model: "3000", deviceJoinName: "Fibaro Switch" } tiles (scale: 2) { @@ -43,15 +43,6 @@ metadata { } preferences { - input ( - title: "Fibaro Double Switch 2 ZW5 manual", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2016/08/switch2_icon.jpg", - url: "http://manuals.fibaro.com/content/manuals/en/FGS-2x3/FGS-2x3-EN-T-v1.2.pdf", - type: "href", - element: "href" - ) - parameterMap().each { input ( title: "${it.num}. ${it.title}", @@ -59,11 +50,12 @@ metadata { type: "paragraph", element: "paragraph" ) - + def defVal = it.def as Integer + def descrDefVal = it.options ? it.options.get(defVal) : defVal input ( name: it.key, title: null, - description: "Default: $it.def" , + description: "$descrDefVal", type: it.type, options: it.options, range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, @@ -304,7 +296,7 @@ def zwaveEvent(physicalgraph.zwave.commands.multichannelassociationv2.MultiChann } //event handlers -def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep=null) { log.debug "BasicReport - "+cmd //ignore } @@ -429,6 +421,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand(cmdVersions()) if (encapsulatedCommand) { logging("${device.displayName} - Parsed MultiChannelCmdEncap ${encapsulatedCommand}") @@ -480,7 +480,7 @@ private encap(Map encapMap) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { logging("${device.displayName} - no encapsulation supported for command: $cmd","info") diff --git a/devicetypes/fibargroup/fibaro-flood-sensor-zw5.src/fibaro-flood-sensor-zw5.groovy b/devicetypes/fibargroup/fibaro-flood-sensor-zw5.src/fibaro-flood-sensor-zw5.groovy index 968f0eccf91..bfead2547e4 100644 --- a/devicetypes/fibargroup/fibaro-flood-sensor-zw5.src/fibaro-flood-sensor-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-flood-sensor-zw5.src/fibaro-flood-sensor-zw5.groovy @@ -17,10 +17,10 @@ metadata { command "forceSync" - fingerprint mfr: "010F", prod: "0B01", model: "1002" - fingerprint mfr: "010F", prod: "0B01", model: "1003" - fingerprint mfr: "010F", prod: "0B01", model: "2002" - fingerprint mfr: "010F", prod: "0B01" + fingerprint mfr: "010F", prod: "0B01", model: "1002", deviceJoinName: "Fibaro Water Leak Sensor" + fingerprint mfr: "010F", prod: "0B01", model: "1003", deviceJoinName: "Fibaro Water Leak Sensor" + fingerprint mfr: "010F", prod: "0B01", model: "2002", deviceJoinName: "Fibaro Water Leak Sensor" + fingerprint mfr: "010F", prod: "0B01", deviceJoinName: "Fibaro Water Leak Sensor" } tiles(scale: 2) { @@ -69,14 +69,13 @@ metadata { preferences { input( - title: "Fibaro Flood Sensor ZW5 manual", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2017/02/fs_icon.png", - url: "http://manuals.fibaro.com/content/manuals/en/FGFS-101/FGFS-101-EN-T-v2.1.pdf", - type: "href", - element: "href" + title: "Fibaro Flood Sensor settings", + description: "Device's settings update is executed when device wakes up.\n" + + "It may take up to 6 hours (for default wake up interval). \n" + + "If you want immediate change, manually wake up device by clicking TMP button once.", + type: "paragraph", + element: "paragraph" ) - parameterMap().each { getPrefsFor(it) } @@ -86,7 +85,7 @@ metadata { } def installed(){ - sendEvent(name: "checkInterval", value: 21600, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: (21600*2)+10*60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } //UI Support functions @@ -170,7 +169,7 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { if (device.currentValue("syncStatus") != "synced") { parameterMap().each { - if (device.currentValue("syncStatus") == "force") { + if (state."$it.key"?.state != null && device.currentValue("syncStatus") == "force") { state."$it.key".state = "notSynced" } @@ -399,6 +398,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand(cmdVersions()) if (encapsulatedCommand) { logging("${device.displayName} - Parsed MultiChannelCmdEncap ${encapsulatedCommand}") @@ -450,7 +457,7 @@ private encap(Map encapMap) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")) { + } else if (zwaveInfo?.cc?.contains("56")) { crcEncap(cmd) } else { logging("${device.displayName} - no encapsulation supported for command: $cmd", "info") diff --git a/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy b/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy index 0d84c708766..2443d2f86cc 100644 --- a/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-motion-sensor-zw5.src/fibaro-motion-sensor-zw5.groovy @@ -25,9 +25,9 @@ metadata { capability "Health Check" capability "Three Axis" - fingerprint mfr: "010F", prod: "0801", model: "2001" - fingerprint mfr: "010F", prod: "0801", model: "1001" - fingerprint mfr: "010F", prod: "0801" + fingerprint mfr: "010F", prod: "0801", model: "2001", deviceJoinName: "Fibaro Motion Sensor" + fingerprint mfr: "010F", prod: "0801", model: "1001", deviceJoinName: "Fibaro Motion Sensor" + fingerprint mfr: "010F", prod: "0801", deviceJoinName: "Fibaro Motion Sensor" } @@ -81,17 +81,15 @@ metadata { details(["FGMS", "battery", "temperature", "illuminance", "motionTile", "multiStatus"]) } preferences { - input( - title: "Fibaro Motion Sensor ZW5 manual", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2017/02/ms_icon.png", - url: "http://manuals.fibaro.com/content/manuals/en/FGMS-001/FGMS-001-EN-T-v2.1.pdf", - type: "href", - element: "href" + title: "Fibaro Motion Sensor settings", + description: "Device's settings update is executed when device wakes up.\n" + + "It may take up to 2 hours (for default wake up interval). \n" + + "If you want immediate change, manually wake up device by clicking B-button once.", + type: "paragraph", + element: "paragraph" ) - - parameterMap().findAll { (it.num as Integer) != 54 }.each { + parameterMap().each { input( title: "${it.num}. ${it.title}", description: it.descr, @@ -103,7 +101,7 @@ metadata { input( name: it.key, title: null, - description: "Default: $descrDefVal", + description: "$descrDefVal", type: it.type, options: it.options, range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, @@ -272,10 +270,6 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { logging("${device.displayName} woke up", "debug") def cmds = [] - if (state.wakeUpInterval?.state == "notSynced" && state.wakeUpInterval?.value != null) { - cmds << zwave.wakeUpV2.wakeUpIntervalSet(seconds: state.wakeUpInterval.value as Integer, nodeid: zwaveHubNodeId) - state.wakeUpInterval.state = "synced" - } def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false) cmds << encap(zwave.batteryV1.batteryGet()) cmds << "delay 500" diff --git a/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy b/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy index ffe3992c369..6fdbc6262d5 100644 --- a/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-single-switch-2-zw5.src/fibaro-single-switch-2-zw5.groovy @@ -14,9 +14,9 @@ metadata { command "reset" - fingerprint mfr: "010F", prod: "0403", model: "3000" - fingerprint mfr: "010F", prod: "0403", model: "2000" - fingerprint mfr: "010F", prod: "0403", model: "1000" + fingerprint mfr: "010F", prod: "0403", model: "3000", deviceJoinName: "Fibaro Switch" + fingerprint mfr: "010F", prod: "0403", model: "2000", deviceJoinName: "Fibaro Switch" + fingerprint mfr: "010F", prod: "0403", model: "1000", deviceJoinName: "Fibaro Switch" } tiles (scale: 2) { @@ -45,15 +45,6 @@ metadata { } preferences { - input ( - title: "Fibaro Single Switch 2 ZW5 manual", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2016/08/switch2_icon.jpg", - url: "http://manuals.fibaro.com/content/manuals/en/FGS-2x3/FGS-2x3-EN-T-v1.2.pdf", - type: "href", - element: "href" - ) - parameterMap().each { input ( title: "${it.num}. ${it.title}", @@ -61,11 +52,12 @@ metadata { type: "paragraph", element: "paragraph" ) - + def defVal = it.def as Integer + def descrDefVal = it.options ? it.options.get(defVal) : defVal input ( name: it.key, title: null, - description: "Default: $it.def" , + description: "$descrDefVal", type: it.type, options: it.options, range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, @@ -310,6 +302,26 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { } } +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + def encapsulatedCommand = cmd.encapsulatedCommand(cmdVersions()) + if (encapsulatedCommand) { + logging("${device.displayName} - Parsed MultiChannelCmdEncap ${encapsulatedCommand}") + // this device sometimes sends events encapsulated. + if (cmd.sourceEndPoint as Integer == 0) zwaveEvent(encapsulatedCommand) + else log.warn "Received a multichannel event from an unsupported channel" + } else { + log.warn "Unable to extract MultiChannel command from $cmd" + } +} + def zwaveEvent(physicalgraph.zwave.Command cmd) { // Handles all Z-Wave commands we aren't interested in log.debug "Unhandled: ${cmd.toString()}" @@ -347,7 +359,7 @@ private encap(Map encapMap) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { logging("no encapsulation supported for command: $cmd","info") diff --git a/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy b/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy index c11624ab369..2f425ade486 100644 --- a/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-wall-plug-eu-zw5.src/fibaro-wall-plug-eu-zw5.groovy @@ -12,8 +12,8 @@ metadata { command "reset" - fingerprint mfr: "010F", prod: "0602", model: "1001", deviceJoinName: "Fibaro Wall Plug EU ZW5" - fingerprint mfr: "010F", prod: "0602" + fingerprint mfr: "010F", prod: "0602", model: "1001", deviceJoinName: "Fibaro Outlet" //Fibaro Wall Plug EU ZW5 + fingerprint mfr: "010F", prod: "0602", deviceJoinName: "Fibaro Outlet" } @@ -45,16 +45,6 @@ metadata { } preferences { - - input ( - title: "Fibaro Wall Plug EU ZW5 manual", - description: "Tap to view the manual.", - image: "http://manuals.fibaro.com/wp-content/uploads/2017/02/wp_icon.png", - url: "http://manuals.fibaro.com/content/manuals/en/FGWPEF-102/FGWPEF-102-EN-A-v2.0.pdf", - type: "href", - element: "href" - ) - parameterMap().each { input ( title: "${it.num}. ${it.title}", @@ -62,11 +52,12 @@ metadata { type: "paragraph", element: "paragraph" ) - + def defVal = it.def as Integer + def descrDefVal = it.options ? it.options.get(defVal) : defVal input ( name: it.key, title: null, - description: "Default: $it.def" , + description: "$descrDefVal", type: it.type, options: it.options, range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, @@ -320,7 +311,7 @@ private crcEncap(physicalgraph.zwave.Command cmd) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { logging("${device.displayName} - no encapsulation supported for command: $cmd","info") diff --git a/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy b/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy index c9f385d29e6..944b2744293 100644 --- a/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy +++ b/devicetypes/fibargroup/fibaro-wall-plug-us-zw5.src/fibaro-wall-plug-us-zw5.groovy @@ -12,8 +12,8 @@ metadata { command "reset" - fingerprint mfr: "010F", prod: "1401", model: "2000" - fingerprint mfr: "010F", prod: "1401" + fingerprint mfr: "010F", prod: "1401", model: "2000", deviceJoinName: "Fibaro Outlet" + fingerprint mfr: "010F", prod: "1401", deviceJoinName: "Fibaro Outlet" } @@ -46,16 +46,6 @@ metadata { } preferences { - - input ( - title: "Fibaro Wall Plug manual", - description: "Tap to view the manual.", - image: "https://s3-eu-west-1.amazonaws.com/fibaro-smartthings/wallPlugUS/plug_us_blue.png", - //url: "http://manuals.fibaro.com/content/manuals/en/FGWPEF-102/FGWPEF-102-EN-A-v2.0.pdf", - type: "href", - element: "href" - ) - parameterMap().each { input ( title: "${it.num}. ${it.title}", @@ -405,6 +395,14 @@ def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationBusy def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand(cmdVersions()) if (encapsulatedCommand) { logging("${device.displayName} - Parsed MultiChannelCmdEncap ${encapsulatedCommand}") @@ -457,7 +455,7 @@ private encap(Map encapMap) { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { logging("${device.displayName} - no encapsulation supported for command: $cmd","info") diff --git a/devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy b/devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy new file mode 100644 index 00000000000..675df2a6b20 --- /dev/null +++ b/devicetypes/fibargroup/fibaro-walli-dimmer-switch.src/fibaro-walli-dimmer-switch.groovy @@ -0,0 +1,465 @@ +/** + * Copyright 2020 SmartThings + * + * Fibaro Walli Dimmer Switch + * + * 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: "Fibaro Walli Dimmer Switch", namespace: "fibargroup", author: "SmartThings", mnmn: "SmartThings", vid: "generic-dimmer-power-energy", ocfDeviceType: "oic.d.switch", runLocally: false, executeCommandsLocally: false) { + + capability "Actuator" + capability "Configuration" + capability "Energy Meter" + capability "Health Check" + capability "Power Meter" + capability "Refresh" + capability "Sensor" + capability "Switch" + capability "Switch Level" + + command "reset" + + // Fibaro Walli Dimmer FGWDEU-111, + // Raw Description: zw:Ls type:1101 mfr:010F prod:1C01 model:1000 ver:5.01 zwv:6.02 lib:03 cc:5E,55,98,56,6C,22 sec:26,85,8E,59,86,72,5A,73,32,70,71,75,5B,7A role:05 ff:9C00 ui:9C00 + fingerprint mfr: "010F", prod: "1C01", model: "1000", deviceJoinName: "Fibaro Dimmer Switch" + } + + tiles(scale: 2) { + multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ + tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff" + attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" + attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff" + attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" + } + tileAttribute ("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action:"switch level.setLevel" + } + } + valueTile("power", "device.power", width: 2, height: 2) { + state "default", label:'${currentValue} W' + } + valueTile("energy", "device.energy", width: 2, height: 2) { + state "default", label:'${currentValue} kWh' + } + standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'reset kWh', action:"reset" + } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + } + + preferences { + // Preferences template begin + parameterMap.each { + input ( + title: it.name, + description: it.description, + type: "paragraph", + element: "paragraph" + ) + + switch(it.type) { + case "boolean": + input( + type: "paragraph", + element: "paragraph", + description: "Option enabled: ${it.activeDescription}\n" + + "Option disabled: ${it.inactiveDescription}" + ) + input( + name: it.key, + type: "boolean", + title: "Enable", + defaultValue: it.defaultValue == it.activeOption, + required: false + ) + break + case "enum": + input( + name: it.key, + title: "Select", + type: "enum", + options: it.values, + defaultValue: it.defaultValue, + required: false + ) + break + case "range": + input( + name: it.key, + type: "number", + title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, + range: it.range, + required: false + ) + break + } + } + // Preferences template end + } + + main(["switch","power","energy"]) + details(["switch", "power", "energy", "refresh", "reset"]) +} + +def getCommandClassVersions() { + [ + // cc: + 0x22: 1, // Application Status + 0x55: 1, // Transport Service + 0x56: 1, // Crc16 Encap + 0x5E: 1, // + 0x6C: 1, // + 0x98: 1, // Security + // sec: + 0x26: 3, // Switch Multilevel + 0x32: 3, // Meter + 0x59: 1, // Association Grp Info + 0x5A: 1, // Device Reset Locally + 0x5B: 2, // Central Scene + 0x70: 2, // Configuration + 0x71: 2, // Notification + 0x72: 2, // Manufacturer Specific + 0x73: 1, // Power Level + 0x75: 2, // Protection + 0x7A: 2, // Firmware Update Md + 0x85: 2, // Association + 0x86: 1, // Version + 0x8E: 2 // Multi Channel Association + ] +} + +def installed() { + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + state.currentPreferencesState."$it.key".status = "synced" + } + // Preferences template end +} + +def updated() { + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + } else if (!state.currentPreferencesState."$it.key".value) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end + + response(refresh()) +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } + sendHubCommand(commands) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + // Preferences template end +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = (value == "default" ? preference.defaultValue : value.intValue()) + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "boolean": + // boolean values are returned as strings from the UI preferences + return settings."$parameterKey" == 'true' ? preference.optionActive : preference.optionInactive + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isPreferenceChanged(preference) { + if (settings."$preference.key" != null) { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } else { + return false + } +} + +// parse events into attributes +def parse(String description) { + //log.debug "description: ${description}" + def result = null + if (description != "updated") { + def cmd = zwave.parse(description, commandClassVersions) + //log.debug "cmd: ${cmd}" + if (cmd) { + result = zwaveEvent(cmd) + //log.debug("'$description' parsed to $result") + } else { + log.debug("Couldn't zwave.parse '$description'") + } + } + result +} + +/* + * Security encapsulation support: + */ +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCommand) { + log.debug "Parsed SecurityMessageEncapsulation into: ${encapsulatedCommand}" + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract Secure command from $cmd" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + dimmerEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + dimmerEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) { + dimmerEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "Unhandled command: ${cmd}" + [:] +} + +def dimmerEvents(physicalgraph.zwave.Command cmd) { + def result = [] + def value = (cmd.value ? "on" : "off") + def switchEvent = createEvent(name: "switch", value: value, descriptionText: "$device.displayName was turned $value") + result << switchEvent + if (cmd.value) { + result << createEvent(name: "level", value: cmd.value == 99 ? 100 : cmd.value , unit: "%") + } + if (switchEvent.isStateChange) { + result << response(["delay 3000", meterGet(scale: 2).format()]) + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + log.debug "v3 Meter report: "+cmd + handleMeterReport(cmd) +} + +def handleMeterReport(cmd) { + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kWh") + } else if (cmd.scale == 1) { + createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kVAh") + } else if (cmd.scale == 2) { + createEvent(name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W") + } + } +} + +def configure() { + log.debug "configure()" + def result = [] + + result << response(encap(meterGet(scale: 0))) + result << response(encap(meterGet(scale: 2))) +} + +def on() { + encapSequence([ + zwave.basicV1.basicSet(value: 0xFF), + zwave.switchMultilevelV1.switchMultilevelGet(), + ], 1000) +} + +def off() { + encapSequence([ + zwave.basicV1.basicSet(value: 0x00), + zwave.switchMultilevelV1.switchMultilevelGet(), + ], 1000) +} + +def setLevel(level, rate = null) { + if(level > 99) level = 99 + encapSequence([ + zwave.basicV1.basicSet(value: level), + zwave.switchMultilevelV1.switchMultilevelGet() + ], 1000) +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + log.debug "ping() called" + refresh() +} + +def refresh() { + log.debug "refresh()" + + encapSequence([ + zwave.switchMultilevelV1.switchMultilevelGet(), + meterGet(scale: 0), + meterGet(scale: 2), + ], 1000) +} + +def reset() { + encapSequence([ + meterReset(), + meterGet(scale: 0) + ]) +} + +def meterGet(scale) { + zwave.meterV2.meterGet(scale) +} + +def meterReset() { + zwave.meterV2.meterReset() +} + +private encapSequence(cmds, Integer delay=250) { + delayBetween(cmds.collect{ encap(it) }, delay) +} + +private encap(physicalgraph.zwave.Command cmd) { + if (zwaveInfo?.zw?.contains("s")) { + secEncap(cmd) + } else { + log.debug "no encapsulation supported for command: $cmd" + cmd.format() + } +} + +private secEncap(physicalgraph.zwave.Command cmd) { + log.debug "encapsulating command using Secure Encapsulation, command: $cmd" + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() +} + +private getParameterMap() {[ + [ + name: "LED frame – colour when ON", key: "ledFrame–ColourWhenOn", type: "enum", + parameterNumber: 11, size: 1, defaultValue: 1, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta", + 8: "colour changes smoothly depending on the measured power", + 9: "colour changes in steps depending on the measured power" + ], + description: "LED colour when the device is ON. When set to 8 or 9, LED frame colour will change depending on the measured power and parameter 10. Other colours are set permanently and do not depend on the power consumption." + ], + [ + name: "LED frame – colour when OFF", key: "ledFrame–ColourWhenOff", type: "enum", + parameterNumber: 12, size: 1, defaultValue: 0, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "LED colour when the device is OFF." + ], + [ + name: "LED frame – brightness", key: "ledFrame–Brightness", type: "range", + parameterNumber: 13, size: 1, defaultValue: 100, + range: "0..102", + description: "Adjust the LED frame brightness. " + + "101 - brightness directly proportional to set level, " + + "102 - brightness inversely proportional to set level" + ], + [ + name: "Manual control – dimming step size", key: "manualControl–DimmingStepSize", type: "range", + parameterNumber: 156, size: 1, defaultValue: 1, + range: "1..99", + description: "Percentage value of the dimming step during the manual control (1 to 99 %)" + ], + [ + name: "Manual control – time of dimming step", key: "manualControl–TimeOfDimmingStep", type: "range", + parameterNumber: 157, size: 2, defaultValue: 5, + range: "0..255", + description: "Time to perform a single dimming step set in the parameter: 'Manual control – dimming step size' during the manual control." + ], + [ + name: "Double click – set level", key: "doubleClick–SetLevel", type: "range", + parameterNumber: 165, size: 1, defaultValue: 99, + range: "0..99", + description: "Brightness level set after double-clicking any of the buttons." + ], + [ + name: "Buttons orientation", key: "buttonsOrientation", type: "boolean", + parameterNumber: 24, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "default (1st button brightens, 2nd button dims)", + optionActive: 1, activeDescription: "reversed (1st button dims, 2nd button brightens)", + description: "Reverse the operation of the buttons." + ] +]} \ No newline at end of file diff --git a/devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy b/devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy new file mode 100644 index 00000000000..a6357b31202 --- /dev/null +++ b/devicetypes/fibargroup/fibaro-walli-double-switch.src/fibaro-walli-double-switch.groovy @@ -0,0 +1,504 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Fibaro Walli Double Switch", namespace: "fibargroup", author: "SmartThings", mnmn: "SmartThings", vid: "generic-switch-power-energy", genericHandler: "Z-Wave") { + capability "Actuator" + capability "Configuration" + capability "Health Check" + capability "Energy Meter" + capability "Power Meter" + capability "Refresh" + capability "Sensor" + capability "Switch" + + command "reset" + + // Fibaro Walli Double Switch FGWDSEU-221 + // Raw Description zw:Ls type:1001 mfr:010F prod:1B01 model:1000 ver:5.01 zwv:6.02 lib:03 cc:5E,55,98,9F,56,6C,22 sec:25,85,8E,59,86,72,5A,73,32,70,71,75,5B,7A,60 role:05 ff:9D00 ui:9D00 epc:2 + fingerprint mfr: "010F", prod: "1B01", model: "1000", deviceJoinName: "Fibaro Switch" + } + + tiles(scale: 2){ + multiAttributeTile(name:"switch", type: "generic", width: 6, height: 4, canChangeIcon: true){ + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState("on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc") + attributeState("off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff") + } + } + valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} W' + } + valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} kWh' + } + standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" + } + standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'reset kWh', action:"reset" + } + + main(["switch"]) + details(["switch","power","energy","refresh","reset"]) + } + + preferences { + // Preferences template begin + parameterMap.each { + input ( + title: it.name, + description: it.description, + type: "paragraph", + element: "paragraph" + ) + + switch(it.type) { + case "boolean": + input( + type: "paragraph", + element: "paragraph", + description: "Option enabled: ${it.activeDescription}\n" + + "Option disabled: ${it.inactiveDescription}" + ) + input( + name: it.key, + type: "boolean", + title: "Enable", + defaultValue: it.defaultValue == it.activeOption, + required: false + ) + break + case "enum": + input( + name: it.key, + title: "Select", + type: "enum", + options: it.values, + defaultValue: it.defaultValue, + required: false + ) + break + case "range": + input( + name: it.key, + type: "number", + title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, + range: it.range, + required: false + ) + break + } + } + // Preferences template end + } +} + +def installed() { + log.debug "Installed ${device.displayName}" + // Device-Watch simply pings if no device events received for checkInterval duration of 32min = 30min + 2min lag time + sendEvent(name: "checkInterval", value: 30 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + state.currentPreferencesState."$it.key".status = "synced" + } + // Preferences template end +} + +def updated() { + sendHubCommand encap(zwave.multiChannelV3.multiChannelEndPointGet()) + + // Preferences template begin + parameterMap.each { + if (state.currentPreferencesState."$it.key".value != settings."$it.key" && settings."$it.key") { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + } else if (!state.currentPreferencesState."$it.key".value) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } + sendHubCommand(commands) +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "boolean": + // boolean values are returned as strings from the UI preferences + return settings."$parameterKey" == 'true' ? preference.optionActive : preference.optionInactive + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +/** + * Mapping of command classes and associated versions used for this DTH + */ +private getCommandClassVersions() { + [ + 0x20: 1, // Basic + 0x25: 1, // Switch Binary + 0x30: 1, // Sensor Binary + 0x31: 2, // Sensor MultiLevel + 0x32: 3, // Meter + 0x56: 1, // Crc16Encap + 0x60: 3, // Multi-Channel + 0x70: 2, // Configuration + 0x72: 2, // Manufacturer Specific + 0x73: 1, // Powerlevel + 0x84: 1, // WakeUp + 0x86: 2, // Version + 0x98: 2 // Security + ] +} + +def configure() { + log.debug "Configure..." + response([ + encap(zwave.multiChannelV3.multiChannelEndPointGet()) + ]) +} + +def parse(String description) { + def result = null + if (description.startsWith("Err")) { + result = createEvent(descriptionText:description, isStateChange:true) + } else if (description != "updated") { + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd, null) + } + } + log.debug "parsed '${description}' to ${result.inspect()}" + result +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd, enpoint = null) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + // Preferences template end +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelEndPointReport cmd, ep = null) { + if(!childDevices) { + addChildSwitches(cmd.endPoints) + } + response([ + refreshAll() + ]) +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd, ep = null) { + log.debug "Security Message Encap ${cmd}" + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand, null) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + log.debug "Multichannel command ${cmd}" + (ep ? " from endpoint $ep" : "") + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + log.debug "Basic ${cmd}" + (ep ? " from endpoint $ep" : "") + handleSwitchReport(ep, cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) { + log.debug "Binary ${cmd}" + (ep ? " from endpoint $ep" : "") + handleSwitchReport(ep, cmd) +} + +private handleSwitchReport(endpoint, cmd) { + def value = cmd.value ? "on" : "off" + endpoint ? changeSwitch(endpoint, value) : [] +} + +private changeSwitch(endpoint, value) { + if (endpoint == 1) { + createEvent(name: "switch", value: value, isStateChange: true, descriptionText: "Switch ${endpoint} is ${value}") + } else { + String childDni = "${device.deviceNetworkId}-$endpoint" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(name: "switch", value: value, isStateChange: true, descriptionText: "Switch ${endpoint} is ${value}") + } +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, ep = null) { + log.debug "Meter ${cmd}" + (ep ? " from endpoint $ep" : "") + if (ep == 1) { + createEvent(createMeterEventMap(cmd)) + } else if(ep) { + String childDni = "${device.deviceNetworkId}-$ep" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(createMeterEventMap(cmd)) + } else { + createEvent([isStateChange: false, descriptionText: "Wattage change has been detected. Refreshing each endpoint"]) + } +} + +private createMeterEventMap(cmd) { + def eventMap = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + } else if (cmd.scale == 2) { + eventMap.name = "power" + eventMap.value = Math.round(cmd.scaledMeterValue) + eventMap.unit = "W" + } + } + eventMap +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, ep) { + log.warn "Unhandled ${cmd}" + (ep ? " from endpoint $ep" : "") +} + +def on() { + onOffCmd(0xFF) +} + +def off() { + onOffCmd(0x00) +} + +def ping() { + refresh() +} + +def childOn(deviceNetworkId = null) { + childOnOff(deviceNetworkId, 0xFF) +} + +def childOff(deviceNetworkId = null) { + childOnOff(deviceNetworkId, 0x00) +} + +def childOnOff(deviceNetworkId, value) { + def switchId = deviceNetworkId ? getSwitchId(deviceNetworkId) : 2 + if (switchId != null) sendHubCommand onOffCmd(value, switchId) +} + +private onOffCmd(value, endpoint = 1) { + delayBetween([ + encap(zwave.basicV1.basicSet(value: value), endpoint), + encap(zwave.basicV1.basicGet(), endpoint) + ], 1000) +} + +private refreshAll(includeMeterGet = true) { + + def endpoints = [1] + + childDevices.each { + def switchId = getSwitchId(it.deviceNetworkId) + if (switchId != null) { + endpoints << switchId + } + } + sendHubCommand refresh(endpoints,includeMeterGet) +} + +def childRefresh(deviceNetworkId = null, includeMeterGet = true) { + def switchId = deviceNetworkId ? getSwitchId(deviceNetworkId) : 2 + if (switchId != null) { + sendHubCommand refresh([switchId],includeMeterGet) + } +} + +def refresh(endpoints = [1], includeMeterGet = true) { + def cmds = [] + endpoints.each { + cmds << [encap(zwave.basicV1.basicGet(), it)] + if (includeMeterGet) { + cmds << encap(zwave.meterV3.meterGet(scale: 0), it) + cmds << encap(zwave.meterV3.meterGet(scale: 2), it) + } + } + delayBetween(cmds, 200) +} + +private resetAll() { + childDevices.each { childReset(it.deviceNetworkId) } + sendHubCommand reset() +} + +def childReset(deviceNetworkId = null) { + def switchId = deviceNetworkId ? getSwitchId(deviceNetworkId) : 2 + if (switchId != null) { + log.debug "Child reset switchId: ${switchId}" + sendHubCommand reset(switchId) + } +} + +def reset(endpoint = 1) { + log.debug "Resetting endpoint: ${endpoint}" + delayBetween([ + encap(zwave.meterV3.meterReset(), endpoint), + encap(zwave.meterV3.meterGet(scale: 0), endpoint), + "delay 500" + ], 500) +} + +def getSwitchId(deviceNetworkId) { + def split = deviceNetworkId?.split("-") + return (split.length > 1) ? split[1] as Integer : null +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + log.debug "encap command: ${cmd} " + if (zwaveInfo.zw.endsWith("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private addChildSwitches(numberOfSwitches) { + for (def endpoint : 2..numberOfSwitches) { + try { + String childDni = "${device.deviceNetworkId}-$endpoint" + def componentLabel = device.displayName + " ${endpoint}" + addChildDevice("Fibaro Double Switch 2 - USB", childDni, device.getHub().getId(), [ + completedSetup : true, + label : componentLabel, + isComponent : false + ]) + } catch(Exception e) { + log.debug "Exception: ${e}" + } + } +} + +private getParameterMap() {[ + [ + name: "LED frame - colour when ON", key: "ledFrame-ColourWhenOn", type: "enum", + parameterNumber: 11, size: 1, defaultValue: 1, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta", + 8: "colour changes smoothly depending on the measured power", + 9: "colour changes in steps depending on the measured power" + ], + description: "LED colour when the device is ON. When set to 8 or 9, LED frame colour will change depending on the measured power and parameter 10. Other colours are set permanently and do not depend on the power consumption." + ], + [ + name: "LED frame - colour when OFF", key: "ledFrame-ColourWhenOff", type: "enum", + parameterNumber: 12, size: 1, defaultValue: 0, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "LED colour when the device is OFF." + ], + [ + name: "LED frame - brightness", key: "ledFrame-Brightness", type: "range", + parameterNumber: 13, size: 1, defaultValue: 100, + range: "1..102", + description: "Adjust the LED frame brightness." + ], + [ + name: "Buttons operation", key: "buttonsOperation", type: "enum", + parameterNumber: 20, size: 1, defaultValue: 1, + values: [ + 1: "1st and 2nd button toggle the load", + 2: "1st button turns the load ON, 2nd button turns the load OFF", + 3: "device works in 2-way/3-way switch configuration" + ], + description: "How device buttons should control the channels." + ], + [ + name: "Buttons orientation", key: "buttonsOrientation", type: "boolean", + parameterNumber: 24, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "default (1st button controls 1st channel, 2nd button controls 2nd channel)", + optionActive: 1, activeDescription: "reversed (1st button controls 2nd channel, 2nd button controls 1st channel)", + description: "Reverse the operation of the buttons." + ], + [ + name: "Outputs orientation", key: "outputsOrientation", type: "boolean", + parameterNumber: 25, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "default (Q1 - 1st channel, Q2 - 2nd channel)", + optionActive: 1, activeDescription: "reversed (Q1 - 2nd channel, Q2 - 1st channel)", + description: "Reverse the operation of Q1 and Q2 without changing the wiring (e.g. in case of invalid connection). Changing orientation turns both outputs off." + ] +]} \ No newline at end of file diff --git a/devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy b/devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy new file mode 100644 index 00000000000..21ae9e826f3 --- /dev/null +++ b/devicetypes/fibargroup/fibaro-walli-roller-shutter-driver.src/fibaro-walli-roller-shutter-driver.groovy @@ -0,0 +1,531 @@ +/** + * Copyright 2020 SmartThings + * + * 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. + * + */ + +import java.lang.Math + +metadata { + definition (name: "Fibaro Walli Roller Shutter Driver", namespace: "fibargroup", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "SmartThings-smartthings-Fibaro_Roller_Shutter") { + capability "Window Shade" + capability "Window Shade Level" + capability "Power Meter" + capability "Energy Meter" + capability "Refresh" + capability "Health Check" + capability "Configuration" + + capability "Switch Level" + } + + tiles(scale: 2) { + multiAttributeTile(name:"windowShade", type: "generic", width: 6, height: 4) { + tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") { + attributeState "open", label: 'Open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing" + attributeState "closed", label: 'Closed', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening" + attributeState "partially open", label: 'Partially open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#d45614", nextState: "closing" + attributeState "opening", label: 'Opening', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "partially open" + attributeState "closing", label: 'Closing', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "partially open" + } + } + standardTile("contPause", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "pause", label:"", icon:'st.sonos.pause-btn', action:'pause', backgroundColor:"#cccccc" + } + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + valueTile("shadeLevel", "device.level", width: 4, height: 1) { + state "level", label: 'Shade is ${currentValue}% up', defaultState: true + } + controlTile("levelSliderControl", "device.level", "slider", width:2, height: 1, inactiveLabel: false) { + state "level", action:"switch level.setLevel" + } + + main "windowShade" + details(["windowShade", "contPause", "shadeLevel", "levelSliderControl", "refresh"]) + } + + preferences { + // Preferences template begin + parameterMap.each { + input (title: it.name, description: it.description, type: "paragraph", element: "paragraph") + + switch(it.type) { + case "boolRange": + input( + name: it.key + "Boolean", type: "bool", title: "Enable", + description: "If you disable this option, it will overwrite setting below.", + defaultValue: it.defaultValue != it.disableValue, required: false + ) + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + case "boolean": + input( + type: "paragraph", element: "paragraph", + description: "Option enabled: ${it.activeDescription}\n Option disabled: ${it.inactiveDescription}" + ) + input( + name: it.key, type: "boolean", + title: "Enable", defaultValue: it.defaultValue == it.activeOption, required: false + ) + break + case "enum": + input( + name: it.key, title: "Select", type: "enum", + options: it.values, defaultValue: it.defaultValue, required: false + ) + break + case "range": + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + } + } + // Preferences template end + } +} + +def installed() { + state.calibrationStatus = "notStarted" + sendEvent(name: "checkInterval", value: 2 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + if (it.type == "boolRange" && getPreferenceValue(it) == it.disableValue) { + state.currentPreferencesState."$it.key".status = "disablePending" + } else { + def preferenceName = it.key + "Boolean" + settings."$preferenceName" = true + state.currentPreferencesState."$it.key".status = "synced" + } + } + // Preferences template end + sendEvent(name: "supportedWindowShadeCommands", value: ["open", "close", "pause"]) +} + +def updated() { + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + if (it.type == "boolRange") { + def preferenceName = it.key + "Boolean" + if (notNullCheck(settings."$preferenceName")) { + if (!settings."$preferenceName") { + state.currentPreferencesState."$it.key".status = "disablePending" + } else if (state.currentPreferencesState."$it.key".status == "disabled") { + state.currentPreferencesState."$it.key".status = "syncPending" + } + } else { + state.currentPreferencesState."$it.key".status = "syncPending" + } + } + } else if (!state.currentPreferencesState."$it.key".value) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } + sendHubCommand(commands) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + handleConfigurationChange(cmd) + } else if (preference.type == "boolRange") { + if (state.currentPreferencesState."$key".status == "disablePending" && preferenceValue == preference.disableValue) { + state.currentPreferencesState."$key".status = "disabled" + } else { + runIn(5, "syncConfiguration", [overwrite: true]) + } + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + // Preferences template end + handleConfigurationChange(cmd) +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "boolean": + return settings."$parameterKey" ? preference.optionActive : preference.optionInactive + case "boolRange": + def parameterKeyBoolean = parameterKey + "Boolean" + return !notNullCheck(settings."$parameterKeyBoolean") || settings."$parameterKeyBoolean" ? settings."$parameterKey" : preference.disableValue + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isPreferenceChanged(preference) { + if (notNullCheck(settings."$preference.key")) { + def value = state.currentPreferencesState."$preference.key" + switch (preference.type) { + case "boolRange": + def boolName = preference.key + "Boolean" + if (state.currentPreferencesState."$preference.key".status == "disabled") { + return settings."$boolName" + } else { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" || !settings."$boolName" + } + default: + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } + } else { + return false + } +} + +private notNullCheck(value) { + return value != null +} + +def handleConfigurationChange(confgurationReport) { + switch (confgurationReport.parameterNumber) { + case 151: //Operating mode + switch(confgurationReport.scaledConfigurationValue) { + case 1: // "Roller blind (with positioning)" + log.info "Changing device type to Fibaro Walli Roller Shutter" + setDeviceType("Fibaro Walli Roller Shutter") + break + case 2: // "Venetian blind (with positioning)" + log.info "Changing device type to Fibaro Walli Roller Shutter Venetian" + setDeviceType("Fibaro Walli Roller Shutter Venetian") + break + case 5: // "Roller blind with built-in driver" + case 6: // "Roller blind with built-in driver (impulse)" + log.info "Device is already configured as Fibaro Walli Roller Shutter Driver" + break + } + break + default: + log.info "Parameter no. ${confgurationReport.parameterNumber} has no specific handler" + break + } +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } else { + log.warn "${device.displayName} - no-parsed event: ${description}" + } + log.debug "Parse returned: ${result}" + return result +} + +def close() { + setShadeLevel(0x64) +} + +def open() { + setShadeLevel(0x00) +} + +def pause() { + encap(zwave.switchMultilevelV3.switchMultilevelStopLevelChange()) +} + +def setLevel(level) { + setShadeLevel(level) +} + +def setShadeLevel(level) { + log.debug "Setting shade level: ${level}" + state.isManualCommand = false + def currentLevel = Integer.parseInt(device.currentState("shadeLevel").value) + state.blindsLastCommand = currentLevel > level ? "opening" : "closing" + state.shadeTarget = level + encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 1) +} + +def refresh() { + sendHubCommand([ + encap(zwave.switchMultilevelV3.switchMultilevelGet()) + ]) +} + +def ping() { + refresh() +} + +def configure() { + def configurationCommands = [] + configurationCommands += encap(zwave.associationV1.associationSet(groupingIdentifier: 2, nodeId: [zwaveHubNodeId])) + configurationCommands += encap(zwave.associationV1.associationSet(groupingIdentifier: 3, nodeId: [zwaveHubNodeId])) + + delayBetween(configurationCommands) +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "unable to extract secure command from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd, ep = null) { + if (cmd.value != 0xFE && ep != 2) { + shadeEvent(cmd.value) + } else { + log.warn "Something went wrong with calibration, position of blind is unknown" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + if (ep != 2) { + shadeEvent(cmd.value) + } +} + +private shadeEvent(value) { + def shadeValue + if (!value) { + shadeValue = "open" + } else if (value == 0x63) { + shadeValue = "closed" + } else { + shadeValue = "partially open" + } + [ + createEvent(name: "windowShade", value: shadeValue, isStateChange: true, descriptionText: "Window blinds is ${shadeValue}"), + createEvent(name: "level", value: value != 0x63 ? value : 100), + createEvent(name: "shadeLevel", value: value != 0x63 ? value : 100) + ] +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, ep = null) { + def toReturn = [] + def eventMap = [:] + def additionalShadeEvent = [:] + if (cmd.meterType == 0x01) { + if (cmd.scale == 0x00) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + toReturn += createEvent(eventMap) + } else if (cmd.scale == 0x02) { + eventMap.name = "power" + eventMap.value = Math.round(cmd.scaledMeterValue) + eventMap.unit = "W" + toReturn += createEvent(eventMap) + if (cmd.scaledMeterValue) { + additionalShadeEvent.name = "windowShade" + additionalShadeEvent.value = state.blindsLastCommand + toReturn += createEvent(additionalShadeEvent) + if (!state.isManualCommand) { + sendEvent(name: "level", value: state.shadeTarget) + sendEvent(name: "shadeLevel", value: state.shadeTarget) + } + } else { + toReturn += response(encap(zwave.switchMultilevelV3.switchMultilevelGet(), 1)) + } + } + } + toReturn +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) { + state.isManualCommand = true + state.blindsLastCommand = cmd.upDown ? "opening" : "closing" +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, ep = null) { + log.warn "Unhandled ${cmd}" + (ep ? " from endpoint $ep" : "") +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private getParameterMap() {[ + [ + name: "LED frame - colour when moving", key: "ledFrame-ColourWhenMoving", type: "enum", + parameterNumber: 11, size: 1, defaultValue: 1, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "This setting defines the LED colour when the motor is running." + ], + [ + name: "LED frame - colour when not moving", key: "ledFrame-ColourWhenNotMoving", type: "enum", + parameterNumber: 12, size: 1, defaultValue: 0, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "This setting defines the LED colour when the motor isn't running." + ], + [ + name: "LED frame - brightness", key: "ledFrame-Brightness", type: "boolRange", + parameterNumber: 13, size: 1, defaultValue: 100, + range: "1..100", disableValue: 0, + description: "This setting allows to adjust the LED frame brightness." + ], + [ + name: "Operating mode", key: "operatingMode", type: "enum", + parameterNumber: 151, size: 1, defaultValue: 1, + values: [ + 1: "Roller blind (with positioning)", + 2: "Venetian blind (with positioning)", + 5: "Roller blind with built-in driver", + 6: "Roller blind with built-in driver (impulse)" + ], + description: "This setting allows adjusting operation according to the connected device." + ], + [ + name: "Delay motor stop after reaching end switch", key: "delayMotorStopAfterReachingEndSwitch", type: "range", + parameterNumber: 154, size: 2, defaultValue: 10, + range: "1..255", + description: "The setting determines the time after which the motor will be stopped after end switch contacts are closed." + ], + [ + name: "Motor operation detection", key: "motorOperationDetection", type: "range", + parameterNumber: 155, size: 2, defaultValue: 10, + range: "1..255", + description: "Power threshold interpreted as reaching a limit switch." + ], + [ + name: "Time of up movement", key: "timeOfUpMovement", type: "range", + parameterNumber: 156, size: 4, defaultValue: 6000, + range: "1..90000", + description: "This setting determines the time needed for roller blinds to reach the top. [100 = 1s]" + ], + [ + name: "Time of down movement", key: "timeOfDownMovement", type: "range", + parameterNumber: 157, size: 4, defaultValue: 6000, + range: "1..90000", + description: "This setting determines time needed for roller blinds to reach the bottom. [100 = 1s]" + ], + [ + name: "Buttons orientation", key: "buttonsOrientation", type: "boolean", + parameterNumber: 24, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "default (1st button UP, 2nd button DOWN)", + optionActive: 1, activeDescription: "reversed (1st button DOWN, 2nd button UP)", + description: "This setting allows reversing the operation of the buttons." + ], + [ + name: "Outputs orientation", key: "outputsOrientation", type: "boolean", + parameterNumber: 25, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "(Q1 - UP, Q2 - DOWN)LED disabled", + optionActive: 1, activeDescription: "reversed (Q1 - DOWN, Q2 - UP)", + description: "This setting allows reversing the operation of Q1 and Q2 without changing the wiring (e.g. in case of invalid motor connection)." + ], + [ + name: "Power reports - include self-consumption", key: "powerReports-IncludeSelf-Consumption", type: "boolean", + parameterNumber: 60, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "Self-consumption not included", + optionActive: 1, activeDescription: "Self-consumption included", + description: "This setting determines whether the power measurements should include power consumed by the device itself." + ], + [ + name: "Power reports - on change", key: "powerReports-OnChange", type: "boolRange", + parameterNumber: 61, size: 2, defaultValue: 15, + range: "1..500", disableValue: 0, + description: "This setting defines minimal change (from the last reported) in measured power that results in sending new report. For loads under 50W the setting is irrelevant, report are sent every 5W change." + ], + [ + name: "Power reports - periodic", key: "powerReports-Periodic", type: "boolRange", + parameterNumber: 62, size: 2, defaultValue: 3600, + range: "30..32400", disableValue: 0, + description: "This setting defines reporting interval for measured power." + ], + [ + name: "Energy reports - on change", key: "energyReports-OnChange", type: "boolRange", + parameterNumber: 65, size: 2, defaultValue: 10, + range: "1..500", disableValue: 0, + description: "This setting defines minimal change (from the last reported) in measured energy that results in sending new report." + ], + [ + name: "Energy reports - periodic", key: "energyReports-Periodic", type: "boolRange", + parameterNumber: 66, size: 2, defaultValue: 3600, + range: "30..32400", disableValue: 0, + description: "This setting defines reporting interval for measured energy." + ] +]} \ No newline at end of file diff --git a/devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy b/devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy new file mode 100644 index 00000000000..7cfbf097669 --- /dev/null +++ b/devicetypes/fibargroup/fibaro-walli-roller-shutter-venetian.src/fibaro-walli-roller-shutter-venetian.groovy @@ -0,0 +1,617 @@ +/** + * Copyright 2020 SmartThings + * + * 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. + * + */ + +import java.lang.Math + +metadata { + definition (name: "Fibaro Walli Roller Shutter Venetian", namespace: "fibargroup", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "SmartThings-smartthings-Fibaro_Roller_Shutter_Venetian", mcdSync: true) { + capability "Window Shade" + capability "Window Shade Level" + capability "Power Meter" + capability "Energy Meter" + capability "Refresh" + capability "Health Check" + capability "Configuration" + + capability "Switch Level" + } + + tiles(scale: 2) { + multiAttributeTile(name:"windowShade", type: "generic", width: 6, height: 4) { + tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") { + attributeState "open", label: 'Open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing" + attributeState "closed", label: 'Closed', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening" + attributeState "partially open", label: 'Partially open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#d45614", nextState: "closing" + attributeState "opening", label: 'Opening', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "partially open" + attributeState "closing", label: 'Closing', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "partially open" + } + } + standardTile("contPause", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "pause", label:"", icon:'st.sonos.pause-btn', action:'pause', backgroundColor:"#cccccc" + } + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + valueTile("shadeLevel", "device.level", width: 4, height: 1) { + state "level", label: 'Shade is ${currentValue}% up', defaultState: true + } + controlTile("levelSliderControl", "device.level", "slider", width:2, height: 1, inactiveLabel: false) { + state "level", action:"switch level.setLevel" + } + + main "windowShade" + details(["windowShade", "contPause", "shadeLevel", "levelSliderControl", "refresh"]) + } + + preferences { + // Preferences template begin + parameterMap.each { + input (title: it.name, description: it.description, type: "paragraph", element: "paragraph") + + switch(it.type) { + case "boolRange": + input( + name: it.key + "Boolean", type: "bool", title: "Enable", + description: "If you disable this option, it will overwrite setting below.", + defaultValue: it.defaultValue != it.disableValue, required: false + ) + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + case "boolean": + input( + type: "paragraph", element: "paragraph", + description: "Option enabled: ${it.activeDescription}\n Option disabled: ${it.inactiveDescription}" + ) + input( + name: it.key, type: "boolean", + title: "Enable", defaultValue: it.defaultValue == it.activeOption, required: false + ) + break + case "enum": + input( + name: it.key, title: "Select", type: "enum", + options: it.values, defaultValue: it.defaultValue, required: false + ) + break + case "range": + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + } + } + // Preferences template end + } +} + +def installed() { + state.calibrationStatus = "notStarted" + sendEvent(name: "checkInterval", value: 2 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + if (it.type == "boolRange" && getPreferenceValue(it) == it.disableValue) { + state.currentPreferencesState."$it.key".status = "disablePending" + } else { + def preferenceName = it.key + "Boolean" + settings."$preferenceName" = true + state.currentPreferencesState."$it.key".status = "synced" + } + } + // Preferences template end + state.timeOfVenetianMovement = 150 + sendEvent(name: "supportedWindowShadeCommands", value: ["open", "close", "pause"]) +} + +def updated() { + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + if (it.type == "boolRange") { + def preferenceName = it.key + "Boolean" + if (notNullCheck(settings."$preferenceName")) { + if (!settings."$preferenceName") { + state.currentPreferencesState."$it.key".status = "disablePending" + } else if (state.currentPreferencesState."$it.key".status == "disabled") { + state.currentPreferencesState."$it.key".status = "syncPending" + } + } else { + state.currentPreferencesState."$it.key".status = "syncPending" + } + statusOverrideIfNeeded(it.key) + } + } else if (!state.currentPreferencesState."$it.key".value) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end + addVenetianBlind() +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } + sendHubCommand(commands) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + if (preference) { + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + handleConfigurationChange(cmd) + } else if (preference.type == "boolRange") { + if (state.currentPreferencesState."$key".status == "disablePending" && preferenceValue == preference.disableValue) { + state.currentPreferencesState."$key".status = "disabled" + } else { + runIn(5, "syncConfiguration", [overwrite: true]) + } + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + } else { + handleConfigurationChange(cmd) + } + // Preferences template end +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "boolean": + return settings."$parameterKey" ? preference.optionActive : preference.optionInactive + case "boolRange": + def parameterKeyBoolean = parameterKey + "Boolean" + return !notNullCheck(settings."$parameterKeyBoolean") || settings."$parameterKeyBoolean" ? settings."$parameterKey" : preference.disableValue + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isPreferenceChanged(preference) { + if (notNullCheck(settings."$preference.key")) { + def value = state.currentPreferencesState."$preference.key" + switch (preference.type) { + case "boolRange": + def boolName = preference.key + "Boolean" + if (state.currentPreferencesState."$preference.key".status == "disabled") { + return settings."$boolName" + } else { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" || !settings."$boolName" + } + default: + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } + } else { + return false + } +} + +private notNullCheck(value) { + return value != null +} + +private statusOverrideIfNeeded(preferenceKey) { + switch (preferenceKey) { + case "forceCalibration": + if (state.calibrationStatus == "done") { + state.currentPreferencesState."$preferenceKey".status = "synced" + } + break + } +} + +def handleConfigurationChange(confgurationReport) { + switch (confgurationReport.parameterNumber) { + case 150: // Calibrating + switch(confgurationReport.scaledConfigurationValue) { + case 0: // "Device is not calibrated" + state.calibrationStatus = "notStarted" + break + case 1: // "Device is calibrated" + state.calibrationStatus = "done" + state.currentPreferencesState.forceCalibration.status = "synced" + break + case 2: // "Force Calibration" + state.calibrationStatus = state.calibrationStatus == "notStarted" ? "pending" : state.calibrationStatus + break + } + log.info "Calibration ${state.calibrationStatus}" + break + case 151: //Operating mode + switch(confgurationReport.scaledConfigurationValue) { + case 1: // "Roller blind (with positioning)" + log.info "Changing device type to Fibaro Walli Roller Shutter" + setDeviceType("Fibaro Walli Roller Shutter") + break + case 2: // "Venetian blind (with positioning)" + log.info "Device is already configured as Fibaro Roller Shutter Venetian" + break + case 5: // "Roller blind with built-in driver" + case 6: // "Roller blind with built-in driver (impulse)" + log.info "Changing device type to Fibaro Walli Roller Shutter Driver" + setDeviceType("Fibaro Walli Roller Shutter Driver") + break + } + break + case 152: // Venetian Blinds - time of full turn of the slats + state.timeOfVenetianMovement = confgurationReport.scaledConfigurationValue + break + default: + log.info "Parameter no. ${confgurationReport.parameterNumber} has no specific handler" + break + } +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } else { + log.warn "${device.displayName} - no-parsed event: ${description}" + } + log.debug "Parse returned: ${result}" + return result +} + +def close() { + setShadeLevel(0x64) +} + +def open() { + setShadeLevel(0x00) +} + +def pause() { + encap(zwave.switchMultilevelV3.switchMultilevelStopLevelChange()) +} + +def setLevel(level) { + setShadeLevel(level) +} + +def setShadeLevel(level) { + log.debug "Setting shade level: ${level}" + state.isManualCommand = false + def currentLevel = Integer.parseInt(device.currentState("shadeLevel").value) + state.blindsLastCommand = currentLevel > level ? "opening" : "closing" + state.shadeTarget = level + encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 1) +} + +def setSlats(childDni, level) { + state.isManualCommand = false + def time = (int) (state.timeOfVenetianMovement * 1.1) + sendHubCommand([ + encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 2), + "delay ${time}", + encap(zwave.switchMultilevelV3.switchMultilevelGet(), 2) + ]) +} + +def refresh() { + sendHubCommand([ + encap(zwave.switchMultilevelV3.switchMultilevelGet(), 1), + "delay 500", + encap(zwave.switchMultilevelV3.switchMultilevelGet(), 2) + ]) +} + +def ping() { + refresh() +} + +def configure() { + encap(zwave.configurationV1.configurationGet(parameterNumber: 152)) +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "unable to extract secure command from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd, ep = null) { + if (cmd.value != 0xFE) { + if (ep != 2) { + shadeEvent(cmd.value) + } else { + String childDni = "${device.deviceNetworkId}:1" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(name: "level", value: cmd.value != 0x63 ? cmd.value : 100) + } + } else { + log.warn "Something went wrong with calibration, position of blind is unknown" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + if (ep != 2) { + shadeEvent(cmd.value) + } +} + +private shadeEvent(value) { + def shadeValue + if (!value) { + shadeValue = "open" + } else if (value == 0x63) { + shadeValue = "closed" + } else { + shadeValue = "partially open" + } + [ + createEvent(name: "windowShade", value: shadeValue, isStateChange: true, descriptionText: "Window blinds is ${shadeValue}"), + createEvent(name: "level", value: value != 0x63 ? value : 100), + createEvent(name: "shadeLevel", value: value != 0x63 ? value : 100) + ] +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, ep = null) { + def toReturn = [] + def eventMap = [:] + def additionalShadeEvent = [:] + if (cmd.meterType == 0x01) { + if (cmd.scale == 0x00) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + toReturn += createEvent(eventMap) + } else if (cmd.scale == 0x02) { + eventMap.name = "power" + eventMap.value = Math.round(cmd.scaledMeterValue) + eventMap.unit = "W" + toReturn += createEvent(eventMap) + if (cmd.scaledMeterValue) { + additionalShadeEvent.name = "windowShade" + additionalShadeEvent.value = state.blindsLastCommand + toReturn += createEvent(additionalShadeEvent) + if (!state.isManualCommand) { + sendEvent(name: "level", value: state.shadeTarget) + sendEvent(name: "shadeLevel", value: state.shadeTarget) + } + } else { + toReturn += response(encap(zwave.switchMultilevelV3.switchMultilevelGet(), 1)) + } + } + } + toReturn +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) { + state.isManualCommand = true + state.blindsLastCommand = cmd.upDown ? "opening" : "closing" +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelSet cmd) { + state.isManualCommand = true + def time = (int) (state.timeOfVenetianMovement * 1.1) + response([ + "delay ${time}", + encap(zwave.switchMultilevelV3.switchMultilevelGet(), 2) + ]) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, ep = null) { + log.warn "Unhandled ${cmd}" + (ep ? " from endpoint $ep" : "") +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private addVenetianBlind() { + if (!childDevices) { + try { + String childDni = "${device.deviceNetworkId}:1" + def componentLabel = "Fibaro Roller Shutter Venetian Blind" + def child = addChildDevice("Child Venetian Blind", childDni, device.getHub().getId(), [ + completedSetup: true, + label : componentLabel, + isComponent : true, + componentName : "venetianBlind", + componentLabel: "Venetian Blind" + ]) + } catch(Exception e) { + log.debug "Exception: ${e}" + } + } +} + +private getParameterMap() {[ + [ + name: "LED frame - colour when moving", key: "ledFrame-ColourWhenMoving", type: "enum", + parameterNumber: 11, size: 1, defaultValue: 1, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "This setting defines the LED colour when the motor is running." + ], + [ + name: "LED frame - colour when not moving", key: "ledFrame-ColourWhenNotMoving", type: "enum", + parameterNumber: 12, size: 1, defaultValue: 0, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "This setting defines the LED colour when the motor isn't running." + ], + [ + name: "LED frame - brightness", key: "ledFrame-Brightness", type: "boolRange", + parameterNumber: 13, size: 1, defaultValue: 100, + range: "1..100", disableValue: 0, + description: "This setting allows to adjust the LED frame brightness." + ], + [ + name: "Force calibration", key: "forceCalibration", type: "boolean", + parameterNumber: 150, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "Blinds are not calibrated.", + optionActive: 2, activeDescription: "Blinds calibration process starts.", + description: "This setting allows triggering blinds calibration process." + ], + [ + name: "Operating mode", key: "operatingMode", type: "enum", + parameterNumber: 151, size: 1, defaultValue: 1, + values: [ + 1: "Roller blind (with positioning)", + 2: "Venetian blind (with positioning)", + 5: "Roller blind with built-in driver", + 6: "Roller blind with built-in driver (impulse)" + ], + description: "This setting allows adjusting operation according to the connected device." + ], + [ + name: "Venetian blind - time of full turn of the slats", key: "venetianBlind-TimeOfFullTurnOfTheSlats", type: "range", + parameterNumber: 152, size: 4, defaultValue: 150, + range: "0..65535", + description: "The setting determines time of full turn cycle of the slats. [100 = 1s]" + ], + [ + name: "Set slats back to previous position", key: "setSlatsBackToPreviousPosition", type: "enum", + parameterNumber: 153, size: 1, defaultValue: 1, + values: [ + 0: "slats return to previously set position only in case of the main controller operation", + 1: "slats return to previously set position in case of the main controller operation, momentary switch operation, or when the limit switch is reached", + 2: "slats return to previously set position in case of the main controller operation, momentary switch operation, when the limit switch is reached or after receiving the Switch Multilevel Stop control frame" + ], + description: "The setting determines slats positioning in various situations." + ], + [ + name: "Delay motor stop after reaching end switch", key: "delayMotorStopAfterReachingEndSwitch", type: "range", + parameterNumber: 154, size: 2, defaultValue: 10, + range: "1..255", + description: "The setting determines the time after which the motor will be stopped after end switch contacts are closed." + ], + [ + name: "Motor operation detection", key: "motorOperationDetection", type: "range", + parameterNumber: 155, size: 2, defaultValue: 10, + range: "1..255", + description: "Power threshold interpreted as reaching a limit switch." + ], + [ + name: "Buttons orientation", key: "buttonsOrientation", type: "boolean", + parameterNumber: 24, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "default (1st button UP, 2nd button DOWN)", + optionActive: 1, activeDescription: "reversed (1st button DOWN, 2nd button UP)", + description: "This setting allows reversing the operation of the buttons." + ], + [ + name: "Outputs orientation", key: "outputsOrientation", type: "boolean", + parameterNumber: 25, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "(Q1 - UP, Q2 - DOWN)LED disabled", + optionActive: 1, activeDescription: "reversed (Q1 - DOWN, Q2 - UP)", + description: "This setting allows reversing the operation of Q1 and Q2 without changing the wiring (e.g. in case of invalid motor connection)." + ], + [ + name: "Power reports - include self-consumption", key: "powerReports-IncludeSelf-Consumption", type: "boolean", + parameterNumber: 60, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "Self-consumption not included", + optionActive: 1, activeDescription: "Self-consumption included", + description: "This setting determines whether the power measurements should include power consumed by the device itself." + ], + [ + name: "Power reports - on change", key: "powerReports-OnChange", type: "boolRange", + parameterNumber: 61, size: 2, defaultValue: 15, + range: "1..500", disableValue: 0, + description: "This setting defines minimal change (from the last reported) in measured power that results in sending new report. For loads under 50W the setting is irrelevant, report are sent every 5W change." + ], + [ + name: "Power reports - periodic", key: "powerReports-Periodic", type: "boolRange", + parameterNumber: 62, size: 2, defaultValue: 3600, + range: "30..32400", disableValue: 0, + description: "This setting defines reporting interval for measured power." + ], + [ + name: "Energy reports - on change", key: "energyReports-OnChange", type: "boolRange", + parameterNumber: 65, size: 2, defaultValue: 10, + range: "1..500", disableValue: 0, + description: "This setting defines minimal change (from the last reported) in measured energy that results in sending new report." + ], + [ + name: "Energy reports - periodic", key: "energyReports-Periodic", type: "boolRange", + parameterNumber: 66, size: 2, defaultValue: 3600, + range: "30..32400", disableValue: 0, + description: "This setting defines reporting interval for measured energy." + ] +]} \ No newline at end of file diff --git a/devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy b/devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy new file mode 100644 index 00000000000..3cb91b3a7ff --- /dev/null +++ b/devicetypes/fibargroup/fibaro-walli-roller-shutter.src/fibaro-walli-roller-shutter.groovy @@ -0,0 +1,554 @@ +/** + * Copyright 2020 SmartThings + * + * 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. + * + */ + +import java.lang.Math + +metadata { + definition (name: "Fibaro Walli Roller Shutter", namespace: "fibargroup", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "SmartThings-smartthings-Fibaro_Roller_Shutter") { + capability "Window Shade" + capability "Window Shade Level" + capability "Power Meter" + capability "Energy Meter" + capability "Refresh" + capability "Health Check" + capability "Configuration" + + capability "Switch Level" + + fingerprint mfr: "010F", prod: "1D01", model: "1000", deviceJoinName: "Fibaro Window Treatment" + } + + tiles(scale: 2) { + multiAttributeTile(name:"windowShade", type: "generic", width: 6, height: 4) { + tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") { + attributeState "open", label: 'Open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing" + attributeState "closed", label: 'Closed', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening" + attributeState "partially open", label: 'Partially open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#d45614", nextState: "closing" + attributeState "opening", label: 'Opening', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "partially open" + attributeState "closing", label: 'Closing', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "partially open" + } + } + standardTile("contPause", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "pause", label:"", icon:'st.sonos.pause-btn', action:'pause', backgroundColor:"#cccccc" + } + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + valueTile("shadeLevel", "device.level", width: 4, height: 1) { + state "level", label: 'Shade is ${currentValue}% up', defaultState: true + } + controlTile("levelSliderControl", "device.level", "slider", width:2, height: 1, inactiveLabel: false) { + state "level", action:"switch level.setLevel" + } + + main "windowShade" + details(["windowShade", "contPause", "shadeLevel", "levelSliderControl", "refresh"]) + } + + preferences { + // Preferences template begin + parameterMap.each { + input (title: it.name, description: it.description, type: "paragraph", element: "paragraph") + + switch(it.type) { + case "boolRange": + input( + name: it.key + "Boolean", type: "bool", title: "Enable", + description: "If you disable this option, it will overwrite setting below.", + defaultValue: it.defaultValue != it.disableValue, required: false + ) + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + case "boolean": + input( + type: "paragraph", element: "paragraph", + description: "Option enabled: ${it.activeDescription}\n Option disabled: ${it.inactiveDescription}" + ) + input( + name: it.key, type: "boolean", + title: "Enable", defaultValue: it.defaultValue == it.activeOption, required: false + ) + break + case "enum": + input( + name: it.key, title: "Select", type: "enum", + options: it.values, defaultValue: it.defaultValue, required: false + ) + break + case "range": + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + } + } + // Preferences template end + } +} + +def installed() { + state.calibrationStatus = "notStarted" + sendEvent(name: "checkInterval", value: 2 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + if (it.type == "boolRange" && getPreferenceValue(it) == it.disableValue) { + state.currentPreferencesState."$it.key".status = "disablePending" + } else { + def preferenceName = it.key + "Boolean" + settings."$preferenceName" = true + state.currentPreferencesState."$it.key".status = "synced" + } + } + // Preferences template end + sendEvent(name: "supportedWindowShadeCommands", value: ["open", "close", "pause"]) +} + +def updated() { + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + if (it.type == "boolRange") { + def preferenceName = it.key + "Boolean" + if (notNullCheck(settings."$preferenceName")) { + if (!settings."$preferenceName") { + state.currentPreferencesState."$it.key".status = "disablePending" + } else if (state.currentPreferencesState."$it.key".status == "disabled") { + state.currentPreferencesState."$it.key".status = "syncPending" + } + } else { + state.currentPreferencesState."$it.key".status = "syncPending" + } + statusOverrideIfNeeded(it.key) + } + } else if (!state.currentPreferencesState."$it.key".value) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } + sendHubCommand(commands) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + handleConfigurationChange(cmd) + } else if (preference.type == "boolRange") { + if (state.currentPreferencesState."$key".status == "disablePending" && preferenceValue == preference.disableValue) { + state.currentPreferencesState."$key".status = "disabled" + } else { + runIn(5, "syncConfiguration", [overwrite: true]) + } + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + // Preferences template end + handleConfigurationChange(cmd) +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "boolean": + return settings."$parameterKey" ? preference.optionActive : preference.optionInactive + case "boolRange": + def parameterKeyBoolean = parameterKey + "Boolean" + return !notNullCheck(settings."$parameterKeyBoolean") || settings."$parameterKeyBoolean" ? settings."$parameterKey" : preference.disableValue + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isPreferenceChanged(preference) { + if (notNullCheck(settings."$preference.key")) { + def value = state.currentPreferencesState."$preference.key" + switch (preference.type) { + case "boolRange": + def boolName = preference.key + "Boolean" + if (state.currentPreferencesState."$preference.key".status == "disabled") { + return settings."$boolName" + } else { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" || !settings."$boolName" + } + default: + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } + } else { + return false + } +} + +private notNullCheck(value) { + return value != null +} + +private statusOverrideIfNeeded(preferenceKey) { + switch (preferenceKey) { + case "forceCalibration": + if (state.calibrationStatus == "done") { + state.currentPreferencesState."$preferenceKey".status = "synced" + } + break + } +} + +def handleConfigurationChange(confgurationReport) { + switch (confgurationReport.parameterNumber) { + case 150: // Calibrating + switch(confgurationReport.scaledConfigurationValue) { + case 0: // "Device is not calibrated" + state.calibrationStatus = "notStarted" + break + case 1: // "Device is calibrated" + state.calibrationStatus = "done" + state.currentPreferencesState.forceCalibration.status = "synced" + break + case 2: // "Force Calibration" + state.calibrationStatus = state.calibrationStatus == "notStarted" ? "pending" : state.calibrationStatus + break + } + log.info "Calibration ${state.calibrationStatus}" + break + case 151: //Operating mode + switch(confgurationReport.scaledConfigurationValue) { + case 1: // "Roller blind (with positioning)" + log.info "Device is already configured as Roller Blind" + break + case 2: // "Venetian blind (with positioning)" + log.info "Changing device type to Fibaro Walli Roller Shutter Venetian" + setDeviceType("Fibaro Walli Roller Shutter Venetian") + break + case 5: // "Roller blind with built-in driver" + case 6: // "Roller blind with built-in driver (impulse)" + log.info "Changing device type to Fibaro Walli Roller Shutter Driver" + setDeviceType("Fibaro Walli Roller Shutter Driver") + break + } + break + default: + log.info "Parameter no. ${confgurationReport.parameterNumber} has no specific handler" + break + } +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } else { + log.warn "${device.displayName} - no-parsed event: ${description}" + } + log.debug "Parse returned: ${result}" + return result +} + +def close() { + setShadeLevel(0x64) +} + +def open() { + setShadeLevel(0x00) +} + +def pause() { + encap(zwave.switchMultilevelV3.switchMultilevelStopLevelChange()) +} + +def setLevel(level) { + setShadeLevel(level) +} + +def setShadeLevel(level) { + log.debug "Setting shade level: ${level}" + state.isManualCommand = false + def currentLevel = Integer.parseInt(device.currentState("shadeLevel").value) + state.blindsLastCommand = currentLevel > level ? "opening" : "closing" + state.shadeTarget = level + encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 1) +} + +def refresh() { + sendHubCommand([ + encap(zwave.switchMultilevelV3.switchMultilevelGet()) + ]) +} + +def ping() { + refresh() +} + +def configure() { + def configurationCommands = [] + configurationCommands += encap(zwave.associationV1.associationSet(groupingIdentifier: 2, nodeId: [zwaveHubNodeId])) + configurationCommands += encap(zwave.associationV1.associationSet(groupingIdentifier: 3, nodeId: [zwaveHubNodeId])) + + delayBetween(configurationCommands) +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "unable to extract secure command from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd, ep = null) { + if (cmd.value != 0xFE && ep != 2) { + shadeEvent(cmd.value) + } else { + log.warn "Something went wrong with calibration, position of blind is unknown" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + if (ep != 2) { + shadeEvent(cmd.value) + } +} + +private shadeEvent(value) { + def shadeValue + if (!value) { + shadeValue = "open" + } else if (value == 0x63) { + shadeValue = "closed" + } else { + shadeValue = "partially open" + } + [ + createEvent(name: "windowShade", value: shadeValue, isStateChange: true, descriptionText: "Window blinds is ${shadeValue}"), + createEvent(name: "level", value: value != 0x63 ? value : 100), + createEvent(name: "shadeLevel", value: value != 0x63 ? value : 100) + ] +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, ep = null) { + def toReturn = [] + def eventMap = [:] + def additionalShadeEvent = [:] + if (cmd.meterType == 0x01) { + if (cmd.scale == 0x00) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + toReturn += createEvent(eventMap) + } else if (cmd.scale == 0x02) { + eventMap.name = "power" + eventMap.value = Math.round(cmd.scaledMeterValue) + eventMap.unit = "W" + toReturn += createEvent(eventMap) + if (cmd.scaledMeterValue) { + additionalShadeEvent.name = "windowShade" + additionalShadeEvent.value = state.blindsLastCommand + toReturn += createEvent(additionalShadeEvent) + if (!state.isManualCommand) { + sendEvent(name: "level", value: state.shadeTarget) + sendEvent(name: "shadeLevel", value: state.shadeTarget) + } + } else { + toReturn += response(encap(zwave.switchMultilevelV3.switchMultilevelGet(), 1)) + } + } + } + toReturn +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelStartLevelChange cmd) { + state.isManualCommand = true + state.blindsLastCommand = cmd.upDown ? "opening" : "closing" +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, ep = null) { + log.warn "Unhandled ${cmd}" + (ep ? " from endpoint $ep" : "") +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private getParameterMap() {[ + [ + name: "LED frame - colour when moving", key: "ledFrame-ColourWhenMoving", type: "enum", + parameterNumber: 11, size: 1, defaultValue: 1, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "This setting defines the LED colour when the motor is running." + ], + [ + name: "LED frame - colour when not moving", key: "ledFrame-ColourWhenNotMoving", type: "enum", + parameterNumber: 12, size: 1, defaultValue: 0, + values: [ + 0: "LED disabled", + 1: "White", + 2: "Red", + 3: "Green", + 4: "Blue", + 5: "Yellow", + 6: "Cyan", + 7: "Magenta" + ], + description: "This setting defines the LED colour when the motor isn't running." + ], + [ + name: "LED frame - brightness", key: "ledFrame-Brightness", type: "boolRange", + parameterNumber: 13, size: 1, defaultValue: 100, + range: "1..100", disableValue: 0, + description: "This setting allows to adjust the LED frame brightness." + ], + [ + name: "Force calibration", key: "forceCalibration", type: "boolean", + parameterNumber: 150, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "Blinds are not calibrated.", + optionActive: 2, activeDescription: "Blinds calibration process starts.", + description: "This setting allows triggering blinds calibration process." + ], + [ + name: "Operating mode", key: "operatingMode", type: "enum", + parameterNumber: 151, size: 1, defaultValue: 1, + values: [ + 1: "Roller blind (with positioning)", + 2: "Venetian blind (with positioning)", + 5: "Roller blind with built-in driver", + 6: "Roller blind with built-in driver (impulse)" + ], + description: "This setting allows adjusting operation according to the connected device." + ], + [ + name: "Delay motor stop after reaching end switch", key: "delayMotorStopAfterReachingEndSwitch", type: "range", + parameterNumber: 154, size: 2, defaultValue: 10, + range: "1..255", + description: "The setting determines the time after which the motor will be stopped after end switch contacts are closed." + ], + [ + name: "Motor operation detection", key: "motorOperationDetection", type: "range", + parameterNumber: 155, size: 2, defaultValue: 10, + range: "1..255", + description: "Power threshold interpreted as reaching a limit switch." + ], + [ + name: "Buttons orientation", key: "buttonsOrientation", type: "boolean", + parameterNumber: 24, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "default (1st button UP, 2nd button DOWN)", + optionActive: 1, activeDescription: "reversed (1st button DOWN, 2nd button UP)", + description: "This setting allows reversing the operation of the buttons." + ], + [ + name: "Outputs orientation", key: "outputsOrientation", type: "boolean", + parameterNumber: 25, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "(Q1 - UP, Q2 - DOWN)LED disabled", + optionActive: 1, activeDescription: "reversed (Q1 - DOWN, Q2 - UP)", + description: "This setting allows reversing the operation of Q1 and Q2 without changing the wiring (e.g. in case of invalid motor connection)." + ], + [ + name: "Power reports - include self-consumption", key: "powerReports-IncludeSelf-Consumption", type: "boolean", + parameterNumber: 60, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "Self-consumption not included", + optionActive: 1, activeDescription: "Self-consumption included", + description: "This setting determines whether the power measurements should include power consumed by the device itself." + ], + [ + name: "Power reports - on change", key: "powerReports-OnChange", type: "boolRange", + parameterNumber: 61, size: 2, defaultValue: 15, + range: "1..500", disableValue: 0, + description: "This setting defines minimal change (from the last reported) in measured power that results in sending new report. For loads under 50W the setting is irrelevant, report are sent every 5W change." + ], + [ + name: "Power reports - periodic", key: "powerReports-Periodic", type: "boolRange", + parameterNumber: 62, size: 2, defaultValue: 3600, + range: "30..32400", disableValue: 0, + description: "This setting defines reporting interval for measured power." + ], + [ + name: "Energy reports - on change", key: "energyReports-OnChange", type: "boolRange", + parameterNumber: 65, size: 2, defaultValue: 10, + range: "1..500", disableValue: 0, + description: "This setting defines minimal change (from the last reported) in measured energy that results in sending new report." + ], + [ + name: "Energy reports - periodic", key: "energyReports-Periodic", type: "boolRange", + parameterNumber: 66, size: 2, defaultValue: 3600, + range: "30..32400", disableValue: 0, + description: "This setting defines reporting interval for measured energy." + ] +]} \ No newline at end of file diff --git a/devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy b/devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy new file mode 100644 index 00000000000..cfc352d7fdc --- /dev/null +++ b/devicetypes/iblinds/iblinds-zwave.src/iblinds-zwave.groovy @@ -0,0 +1,357 @@ +/** + * Copyright 2020 SmartThings + * + * 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. + * + */ +import groovy.json.JsonOutput + + +metadata { + definition (name: "iblinds Z-Wave", namespace: "iblinds", author: "HABHomeIntel", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-shade-3") { + capability "Window Shade" + capability "Window Shade Preset" + capability "Switch Level" + capability "Battery" + capability "Refresh" + capability "Actuator" + capability "Health Check" + + command "stop" + + fingerprint mfr:"0287", prod:"0003", model:"000D", deviceJoinName: "iBlinds Window Treatment" + fingerprint mfr:"0287", prod:"0004", model:"0071", deviceJoinName: "iBlinds Window Treatment" + } + + simulator { + status "open": "command: 2603, payload: FF" + status "closed": "command: 2603, payload: 00" + status "10%": "command: 2603, payload: 0A" + status "66%": "command: 2603, payload: 42" + status "99%": "command: 2603, payload: 63" + status "battery 100%": "command: 8003, payload: 64" + status "battery low": "command: 8003, payload: FF" + + // reply messages + reply "2001FF,delay 1000,2602": "command: 2603, payload: 10 FF FE" + reply "200100,delay 1000,2602": "command: 2603, payload: 60 00 FE" + reply "200142,delay 1000,2602": "command: 2603, payload: 10 42 FE" + reply "200163,delay 1000,2602": "command: 2603, payload: 10 63 FE" + } + + tiles(scale: 2) { + multiAttributeTile(name:"windowShade", type: "lighting", width: 6, height: 4){ + tileAttribute ("device.windowShade", key: "PRIMARY_CONTROL") { + attributeState "open", label:'${name}', action:"close", icon:"http://i.imgur.com/4TbsR54.png", backgroundColor:"#79b821", nextState:"closing" + attributeState "closed", label:'${name}', action:"open", icon:"st.shades.shade-closed", backgroundColor:"#ffffff", nextState:"opening" + attributeState "partially open", label:'Open', action:"close", icon:"st.shades.shade-open", backgroundColor:"#79b821", nextState:"closing" + attributeState "opening", label:'${name}', action:"stop", icon:"st.shades.shade-opening", backgroundColor:"#79b821", nextState:"partially open" + attributeState "closing", label:'${name}', action:"stop", icon:"st.shades.shade-closing", backgroundColor:"#ffffff", nextState:"partially open" + } + tileAttribute ("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action:"setLevel" + } + } + + standardTile("home", "device.level", width: 2, height: 2, decoration: "flat") { + state "default", label: "home", action:"presetPosition", icon:"st.Home.home2" + } + + standardTile("refresh", "device.refresh", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh", nextState: "disabled" + state "disabled", label:'', action:"", icon:"st.secondary.refresh" + } + + valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) { + state "battery", label:'${currentValue}% battery', unit:"" + } + + preferences { + // V3 configuration + input title: "V3 iBlinds Device Config", description: "Configuration options for newer V3 iBlinds devices", type: "paragraph", element: "paragraph", displayDuringSetup: false + input name: "NVM_TightLevel", type: "number", title: "Close Interval", defaultValue: 22, description: "Used for Large and Heavy blinds to set the close interval. A smaller value will make the blinds close tighter", required: true, displayDuringSetup: true + input name: "NVM_Direction", type: "bool", title: "Reverse", description: "Reverse Blind Direction", defaultValue: false + input name: "NVM_Target_Value", type: "number", title: "Default ON Value", defaultValue: 50, range: "1..100", description: "Used to set the default ON level when manual push button is pushed", required: true, displayDuringSetup:false + input name: "NVM_Device_Reset_Support", type: "bool", title: "Disable Reset Button", description: "Used for situations where the top motor buttons are being pushed accidentally via a tight installation space, etc.", defaultValue: false + input name: "Speed_Parameter", type: "number", title: "Open/Close Speed (seconds)", defaultValue: 0, range:"0..100", description: "To slow down the blinds, increase the value", required: true, displayDuringSetup: false + + input title: "", description: "", type: "paragraph", element: "paragraph", displayDuringSetup: false + + // V2 configuration + input title: "V2 iBlinds Device Config", description: "Configuration options for older V2 iBlinds devices", type: "paragraph", element: "paragraph", displayDuringSetup: false + input "preset", "number", title: "Preset position", description: "Set the window shade preset position", defaultValue: 50, range: "1..99", required: false, displayDuringSetup: false + input "reverse", "bool", title: "Reverse", description: "Reverse Blind Direction", defaultValue: false, required: false , displayDuringSetup: false + } + + main(["windowShade"]) + details(["windowShade", "home", "refresh", "battery"]) + } +} + +def parse(String description) { + def result = null + //if (description =~ /command: 2603, payload: ([0-9A-Fa-f]{6})/) + // TODO: Workaround manual parsing of v4 multilevel report + def cmd = zwave.parse(description, [0x20: 1, 0x26: 3]) // TODO: switch to SwitchMultilevel v4 and use target value + + if (cmd) { + result = zwaveEvent(cmd) + } + log.debug "Parsed '$description' to ${result?.inspect()}" + + return result +} + +def getCheckInterval() { + // iblinds is a battery-powered device, and it's not very critical + // to know whether they're online or not – 12 hrs + 12 * 60 * 60 //12 hours +} + +def installed() { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close"]), displayed: false) + + storeParamState() + + response(initialize() + refresh()) +} + +def updated() { + def cmds = [] + + if (device.latestValue("checkInterval") != checkInterval) { + sendEvent(name: "checkInterval", value: checkInterval, displayed: false) + } + + cmds += configureParams() + storeParamState() + cmds += initialize() + + response(cmds) +} + +def initialize() { + def cmds = [] + + if (isV3Device()) { + // Set up lifeline association + cmds << zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId).format() + } + + // Schedule daily battery check + unschedule() + runIn(15, getBattery) + schedule("2020-01-01T12:01:00.000-0600", getBattery) + + cmds +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + handleLevelReport(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { + handleLevelReport(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) { + handleLevelReport(cmd) +} + +private handleLevelReport(physicalgraph.zwave.Command cmd) { + def level = cmd.value as Integer + def result = [] + + log.debug "handleLevelReport($level)" + + if (!state.lastbatt || now() - state.lastbatt > 24 * 60 * 60 * 1000) { + log.debug "requesting battery" + state.lastbatt = (now() - 23 * 60 * 60 * 1000) // don't queue up multiple battery reqs in a row + result << response(["delay 15000", zwave.batteryV1.batteryGet().format()]) + } + result +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelStopLevelChange cmd) { + [ createEvent(name: "windowShade", value: "partially open", displayed: false, descriptionText: "$device.displayName shade stopped"), + response(zwave.switchMultilevelV1.switchMultilevelGet().format()) ] +} + +def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + def map = [ name: "battery", unit: "%" ] + if (cmd.batteryLevel == 0xFF) { + map.value = 1 + map.descriptionText = "${device.displayName} has a low battery" + map.isStateChange = true + } else { + map.value = cmd.batteryLevel + } + state.lastbatt = now() + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.debug "unhandled $cmd" + return [] +} + +def open() { + Integer level = isV3Device() ? (NVM_Target_Value ?: 50) : 50 // Blinds fully open at 50%, NVM_Target_Value can't be 0% + log.debug "open()" + + sendEvent(name: "windowShade", value: "open") + sendEvent(name: "level", value: level, unit: "%", displayed: true) + + zwave.switchMultilevelV3.switchMultilevelSet(value: level).format() +} + +def close() { + log.debug "close()" + Integer level = isV3Device() ? 0 : (reverse ? 99 : 0) + + sendEvent(name: "windowShade", value: "closed") + sendEvent(name: "level", value: 0, unit: "%", displayed: true) + + zwave.switchMultilevelV3.switchMultilevelSet(value: level).format() +} + +def setLevel(value, duration = null) { + def descriptionText = null + + log.debug "setLevel(${value.inspect()})" + Integer level = value as Integer + + if (level < 0) level = 0 + if (level > 99) level = 99 + Integer tiltLevel = level as Integer // we will use this value to decide what level is sent to device (reverse or not reversed) + + // For older devices, check to see if user wants blinds to operate in reverse direction + if (!isV3Device() && reverse) { + tiltLevel = 99 - level + } + + if (level <= 0) { + sendEvent(name: "windowShade", value: "closed") + } else if (level >= 99) { + level = 99 + sendEvent(name: "windowShade", value: "closed") + } else if (level == 50) { + sendEvent(name: "windowShade", value: "open") + } else { + descriptionText = "${device.displayName} tilt level is ${level}% open" + sendEvent(name: "windowShade", value: "partially open" , descriptionText: descriptionText) //, isStateChange: levelEvent.isStateChange ) + } + //log.debug "Level - ${level}% & Tilt Level - ${tiltLevel}%" + sendEvent(name: "level", value: level, descriptionText: descriptionText) + zwave.switchMultilevelV3.switchMultilevelSet(value: tiltLevel).format() +} + +def presetPosition() { + isV3Device() ? open() : setLevel(preset ?: 50) +} + +def pause() { + log.debug "pause()" + stop() +} + +def stop() { + log.debug "stop()" + zwave.switchMultilevelV3.switchMultilevelStopLevelChange().format() +} + +def ping() { + refresh() +} + +def refresh() { + log.debug "refresh()" + delayBetween([ + zwave.switchMultilevelV1.switchMultilevelGet().format(), + zwave.batteryV1.batteryGet().format() + ], 1500) +} + +def configureParams() { + def cmds = [] + + if (isV3Device()) { + /* + Parameter No. Size Parameter Name Desc. + 1 1 NVM_TightLevel Auto Calibration tightness + 2 1 NVM_Direction Reverse the direction of iblinds + 3 1 NVM_Target_Report Not used **** + 4 1 NVM_Target_Value Default on position + 5 1 NVM_Device_Reset_Support Turns off the reset button + 6 1 Speed_Parameter Speed + */ + + log.debug "Configuration Started" + + // If paramater value has changed then add zwave configration command to cmds + + if (NVM_TightLevel != null && state.param1 != NVM_TightLevel) { + cmds << zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [NVM_TightLevel.toInteger()]).format() + } + if (NVM_Direction != null && state.param2 != NVM_Direction) { + def NVM_Direction_Val = boolToInteger(NVM_Direction) + + cmds << zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, configurationValue: [NVM_Direction_Val.toInteger()]).format() + } + if (state.param3 != 0) { + cmds << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, configurationValue: [0]).format() + } + if (NVM_Target_Value != null && state.param4 != NVM_Target_Value) { + cmds << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, configurationValue: [NVM_Target_Value.toInteger()]).format() + } + if (NVM_Device_Reset_Support != null && state.param5 != NVM_Device_Reset_Support) { + def NVM_Device_Reset_Val = boolToInteger(NVM_Device_Reset_Support) + + cmds << zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, configurationValue: [NVM_Device_Reset_Val.toInteger()]).format() + } + if (Speed_Parameter != null && state.param6 != Speed_Parameter) { + cmds << zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, configurationValue: [Speed_Parameter.toInteger()]).format() + } + + log.debug "Configuration Complete" + } + + delayBetween(cmds, 500) +} + +private storeParamState() { + if (isV3Device()) { + log.debug "Storing Paramater Values" + + state.param1 = NVM_TightLevel + state.param2 = NVM_Direction + state.param3 = 0 // Not used at the moment + state.param4 = NVM_Target_Value + state.param5 = NVM_Device_Reset_Support + state.param6 = Speed_Parameter + } +} + +def boolToInteger(boolValue) { + boolValue ? 1 : 0 +} + +def getBattery() { + log.debug "get battery level" + // Use sendHubCommand to get battery level + def cmd = [] + cmd << new physicalgraph.device.HubAction(zwave.batteryV1.batteryGet().format()) + sendHubCommand(cmd) +} + +def isV3Device() { + zwaveInfo.mfr == "0287" && zwaveInfo.prod == "0004" && zwaveInfo.model == "0071" +} diff --git a/devicetypes/keen-home/keen-home-smart-vent.src/keen-home-smart-vent.groovy b/devicetypes/keen-home/keen-home-smart-vent.src/keen-home-smart-vent.groovy index 8594add1866..69df0f40310 100644 --- a/devicetypes/keen-home/keen-home-smart-vent.src/keen-home-smart-vent.groovy +++ b/devicetypes/keen-home/keen-home-smart-vent.src/keen-home-smart-vent.groovy @@ -1,9 +1,11 @@ +import physicalgraph.zigbee.zcl.DataType + // keen home smart vent // http://www.keenhome.io // SmartThings Device Handler v1.0.0 metadata { - definition (name: "Keen Home Smart Vent", namespace: "Keen Home", author: "Keen Home") { + definition (name: "Keen Home Smart Vent", namespace: "Keen Home", author: "Keen Home", ocfDeviceType: "x.com.st.d.vent") { capability "Switch Level" capability "Switch" capability "Configuration" @@ -12,16 +14,9 @@ metadata { capability "Temperature Measurement" capability "Battery" capability "Health Check" + capability "Atmospheric Pressure Measurement" - command "getLevel" - command "getOnOff" - command "getPressure" - command "getBattery" - command "getTemperature" - command "setZigBeeIdTile" - command "clearObstruction" - - fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02", outClusters: "0019" + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02", outClusters: "0019", deviceJoinName: "Keen Home Vent" } // simulator metadata @@ -40,8 +35,6 @@ metadata { standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { state "on", action: "switch.off", icon: "st.vents.vent-open-text", backgroundColor: "#00a0dc" state "off", action: "switch.on", icon: "st.vents.vent-closed", backgroundColor: "#ffffff" - state "obstructed", action: "clearObstruction", icon: "st.vents.vent-closed", backgroundColor: "#e86d13" - state "clearing", action: "", icon: "st.vents.vent-closed", backgroundColor: "#ffffff" } controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) { state "level", action:"switch level.setLevel" @@ -51,423 +44,113 @@ metadata { } valueTile("temperature", "device.temperature", inactiveLabel: false) { state "temperature", label:'${currentValue}°', - backgroundColors:[ - [value: 31, color: "#153591"], - [value: 44, color: "#1e9cbb"], - [value: 59, color: "#90d2a7"], - [value: 74, color: "#44b621"], - [value: 84, color: "#f1d801"], - [value: 95, color: "#d04e00"], - [value: 96, color: "#bc2323"] - ] + backgroundColors:[ + // Celsius + [value: 0, color: "#153591"], + [value: 7, color: "#1e9cbb"], + [value: 15, color: "#90d2a7"], + [value: 23, color: "#44b621"], + [value: 28, color: "#f1d801"], + [value: 35, color: "#d04e00"], + [value: 37, color: "#bc2323"], + // Fahrenheit + [value: 40, color: "#153591"], + [value: 44, color: "#1e9cbb"], + [value: 59, color: "#90d2a7"], + [value: 74, color: "#44b621"], + [value: 84, color: "#f1d801"], + [value: 95, color: "#d04e00"], + [value: 96, color: "#bc2323"] + ] } valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { state "battery", label: 'Battery \n${currentValue}%', backgroundColor:"#ffffff" } - valueTile("zigbeeId", "device.zigbeeId", inactiveLabel: true, decoration: "flat") { - state "serial", label:'${currentValue}', backgroundColor:"#ffffff" - } main "switch" details(["switch","refresh","temperature","levelSliderControl","battery"]) } } -/**** PARSE METHODS ****/ +def getPRESSURE_MEASUREMENT_CLUSTER() {0x0403} +def getMFG_CODE() {0x115B} + def parse(String description) { log.debug "description: $description" - - Map map = [:] - if (description?.startsWith('catchall:')) { - map = parseCatchAllMessage(description) - } - else if (description?.startsWith('read attr -')) { - map = parseReportAttributeMessage(description) - } - else if (description?.startsWith('temperature: ') || description?.startsWith('humidity: ')) { - map = parseCustomMessage(description) - } - else if (description?.startsWith('on/off: ')) { - map = parseOnOffMessage(description) - } - - log.debug "Parse returned $map" - return map ? createEvent(map) : null -} - -private Map parseCatchAllMessage(String description) { - log.debug "parseCatchAllMessage" - - def cluster = zigbee.parse(description) - log.debug "cluster: ${cluster}" - if (shouldProcessMessage(cluster)) { - log.debug "processing message" - switch(cluster.clusterId) { - case 0x0001: - return makeBatteryResult(cluster.data.last()) - break - - case 0x0402: - // temp is last 2 data values. reverse to swap endian - String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join() - def value = convertTemperatureHex(temp) - return makeTemperatureResult(value) - break - - case 0x0006: - return makeOnOffResult(cluster.data[-1]) - break + def event = zigbee.getEvent(description) + if (!event) { + Map descMap = zigbee.parseDescriptionAsMap(description) + if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.attrInt == 0x0021) { + event = getBatteryPercentageResult(Integer.parseInt(descMap.value, 16)) + } else if (descMap?.clusterInt == PRESSURE_MEASUREMENT_CLUSTER && descMap.attrInt == 0x0020) { + // manufacturer-specific attribute + event = getPressureResult(Integer.parseInt(descMap.value, 16)) + } + } else if (event.name == "level") { + if (event.value > 0 && device.currentValue("switch") == "off") { + sendEvent([name: "switch", value: "on"]) } } - return [:] -} - -private boolean shouldProcessMessage(cluster) { - // 0x0B is default response indicating message got through - // 0x07 is bind message - if (cluster.profileId != 0x0104 || - cluster.command == 0x0B || - cluster.command == 0x07 || - (cluster.data.size() > 0 && cluster.data.first() == 0x3e)) { - return false - } - - return true -} - -private Map parseReportAttributeMessage(String description) { - log.debug "parseReportAttributeMessage" - - Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param -> - def nameAndValue = param.split(":") - map += [(nameAndValue[0].trim()):nameAndValue[1].trim()] - } - log.debug "Desc Map: $descMap" - - if (descMap.cluster == "0006" && descMap.attrId == "0000") { - return makeOnOffResult(Int.parseInt(descMap.value)); - } - else if (descMap.cluster == "0008" && descMap.attrId == "0000") { - return makeLevelResult(descMap.value) - } - else if (descMap.cluster == "0402" && descMap.attrId == "0000") { - def value = convertTemperatureHex(descMap.value) - return makeTemperatureResult(value) - } - else if (descMap.cluster == "0001" && descMap.attrId == "0021") { - return makeBatteryResult(Integer.parseInt(descMap.value, 16)) - } - else if (descMap.cluster == "0403" && descMap.attrId == "0020") { - return makePressureResult(Integer.parseInt(descMap.value, 16)) - } - else if (descMap.cluster == "0000" && descMap.attrId == "0006") { - return makeSerialResult(new String(descMap.value.decodeHex())) - } - - // shouldn't get here - return [:] -} - -private Map parseCustomMessage(String description) { - Map resultMap = [:] - if (description?.startsWith('temperature: ')) { - def tempData = description.split(": ")[1].split(" ") - def scale = (tempData.length > 1) ? tempData[1] : "C" - def value = Double.parseDouble(tempData[0]) - resultMap = makeTemperatureResult(convertTemperature(value, scale)) - } - return resultMap -} - -private Map parseOnOffMessage(String description) { - Map resultMap = [:] - if (description?.startsWith('on/off: ')) { - def value = Integer.parseInt(description - "on/off: ") - resultMap = makeOnOffResult(value) - } - return resultMap -} - -private Map makeOnOffResult(rawValue) { - log.debug "makeOnOffResult: ${rawValue}" - def linkText = getLinkText(device) - def value = rawValue == 1 ? "on" : "off" - return [ - name: "switch", - value: value, - descriptionText: "${linkText} is ${value}" - ] + log.debug "parsed event: $event" + createEvent(event) } -private Map makeLevelResult(rawValue) { - def linkText = getLinkText(device) - def value = Integer.parseInt(rawValue, 16) - def rangeMax = 254 +def getBatteryPercentageResult(rawValue) { + // reports raw percentage, not 2x + def result = [:] - // catch obstruction level - if (value == 255) { - log.debug "${linkText} is obstructed" - // Just return here. Once the vent is power cycled - // it will go back to the previous level before obstruction. - // Therefore, no need to update level on the display. - return [ - name: "switch", - value: "obstructed", - descriptionText: "${linkText} is obstructed. Please power cycle." - ] + if (0 <= rawValue && rawValue <= 100) { + result.name = 'battery' + result.translatable = true + result.descriptionText = "${device.displayName} battery was ${rawValue}%" + result.value = Math.round(rawValue) } - value = Math.floor(value / rangeMax * 100) - - return [ - name: "level", - value: value, - descriptionText: "${linkText} level is ${value}%" - ] -} - -private Map makePressureResult(rawValue) { - log.debug 'makePressureResut' - def linkText = getLinkText(device) - - def pascals = rawValue / 10 - def result = [ - name: 'pressure', - descriptionText: "${linkText} pressure is ${pascals}Pa", - value: pascals - ] - return result } -private Map makeBatteryResult(rawValue) { - // log.debug 'makeBatteryResult' - def linkText = getLinkText(device) - - // log.debug - [ - name: 'battery', - value: rawValue, - descriptionText: "${linkText} battery is at ${rawValue}%" - ] -} - -private Map makeTemperatureResult(value) { - // log.debug 'makeTemperatureResult' - def linkText = getLinkText(device) - - // log.debug "tempOffset: ${tempOffset}" - if (tempOffset) { - def offset = tempOffset as int - // log.debug "offset: ${offset}" - def v = value as int - // log.debug "v: ${v}" - value = v + offset - // log.debug "value: ${value}" - } - - return [ - name: 'temperature', - value: "" + value, - descriptionText: "${linkText} is ${value}°${temperatureScale}", - unit: temperatureScale - ] -} - -/**** HELPER METHODS ****/ -private def convertTemperatureHex(value) { - // log.debug "convertTemperatureHex(${value})" - def celsius = Integer.parseInt(value, 16).shortValue() / 100 - // log.debug "celsius: ${celsius}" - - return convertTemperature(celsius, "C") -} - -private def convertTemperature(value, scale = "C") { - if(getTemperatureScale() == scale){ - return Math.round(value * 100) / 100 - } else { - if (scale == "C") { - // Celsius to Fahrenheit - return Math.round(celsiusToFahrenheit(value) * 100) /100 - } - // Fahrenheit to Celsius - return Math.round(fahrenheitToCelsius(value) * 100) /100 - } -} - -private def makeSerialResult(serial) { - log.debug "makeSerialResult: " + serial - - def linkText = getLinkText(device) - sendEvent([ - name: "serial", - value: serial, - descriptionText: "${linkText} has serial ${serial}" ]) - return [ - name: "serial", - value: serial, - descriptionText: "${linkText} has serial ${serial}" ] -} - -// takes a level from 0 to 100 and translates it to a ZigBee move to level with on/off command -private def makeLevelCommand(level) { - def rangeMax = 254 - def scaledLevel = Math.round(level * rangeMax / 100) - log.debug "scaled level for ${level}%: ${scaledLevel}" - - // convert to hex string and pad to two digits - def hexLevel = new BigInteger(scaledLevel.toString()).toString(16).padLeft(2, '0') - - "st cmd 0x${device.deviceNetworkId} 1 8 4 {${hexLevel} 0000}" +def getPressureResult(rawValue) { + def kpa = rawValue / (10 * 1000) // reports are in deciPascals + return [name: "atmosphericPressure", value: kpa, unit: "kPa"] } /**** COMMAND METHODS ****/ def on() { - def linkText = getLinkText(device) - log.debug "open ${linkText}" - - // only change the state if the vent is not obstructed - if (device.currentValue("switch") == "obstructed") { - log.error("cannot open because ${linkText} is obstructed") - return + def cmds = [] + def currentLevel = device.currentValue("level") + if (currentLevel != null) { + currentLevel = currentLevel as int } - - sendEvent(makeOnOffResult(1)) - "st cmd 0x${device.deviceNetworkId} 1 6 1 {}" + def levelToSet = currentLevel ? currentLevel : 100 + cmds << zigbee.setLevel(levelToSet) } def off() { - def linkText = getLinkText(device) - log.debug "close ${linkText}" - - // only change the state if the vent is not obstructed - if (device.currentValue("switch") == "obstructed") { - log.error("cannot close because ${linkText} is obstructed") - return - } - - sendEvent(makeOnOffResult(0)) - "st cmd 0x${device.deviceNetworkId} 1 6 0 {}" -} - -def clearObstruction() { - def linkText = getLinkText(device) - log.debug "attempting to clear ${linkText} obstruction" - - sendEvent([ - name: "switch", - value: "clearing", - descriptionText: "${linkText} is clearing obstruction" - ]) - - // send a move command to ensure level attribute gets reset for old, buggy firmware - // then send a reset to factory defaults - // finally re-configure to ensure reports and binding is still properly set after the rtfd - [ - makeLevelCommand(device.currentValue("level")), "delay 500", - "st cmd 0x${device.deviceNetworkId} 1 0 0 {}", "delay 5000" - ] + configure() + zigbee.off() } def setLevel(value, rate = null) { log.debug "setting level: ${value}" - def linkText = getLinkText(device) - - // only change the level if the vent is not obstructed - def currentState = device.currentValue("switch") - - if (currentState == "obstructed") { - log.error("cannot set level because ${linkText} is obstructed") - return - } - - sendEvent(name: "level", value: value) - if (value > 0) { - sendEvent(name: "switch", value: "on", descriptionText: "${linkText} is on by setting a level") - } - else { - sendEvent(name: "switch", value: "off", descriptionText: "${linkText} is off by setting level to 0") - } - - makeLevelCommand(value) -} - -def getOnOff() { - log.debug "getOnOff()" - - // disallow on/off updates while vent is obstructed - if (device.currentValue("switch") == "obstructed") { - log.error("cannot update open/close status because ${getLinkText(device)} is obstructed") - return [] - } - - ["st rattr 0x${device.deviceNetworkId} 1 0x0006 0"] -} - -def getPressure() { - log.debug "getPressure()" - - // using a Keen Home specific attribute in the pressure measurement cluster - [ - "zcl mfg-code 0x115B", "delay 200", - "zcl global read 0x0403 0x20", "delay 200", - "send 0x${device.deviceNetworkId} 1 1", "delay 200" - ] -} - -def getLevel() { - log.debug "getLevel()" - - // disallow level updates while vent is obstructed - if (device.currentValue("switch") == "obstructed") { - log.error("cannot update level status because ${getLinkText(device)} is obstructed") - return [] - } - - ["st rattr 0x${device.deviceNetworkId} 1 0x0008 0x0000"] -} - -def getTemperature() { - log.debug "getTemperature()" - - ["st rattr 0x${device.deviceNetworkId} 1 0x0402 0"] -} - -def getBattery() { - log.debug "getBattery()" - - ["st rattr 0x${device.deviceNetworkId} 1 0x0001 0x0021"] -} - -def setZigBeeIdTile() { - log.debug "setZigBeeIdTile() - ${device.zigbeeId}" - - def linkText = getLinkText(device) - - sendEvent([ - name: "zigbeeId", - value: device.zigbeeId, - descriptionText: "${linkText} has zigbeeId ${device.zigbeeId}" ]) - return [ - name: "zigbeeId", - value: device.zigbeeId, - descriptionText: "${linkText} has zigbeeId ${device.zigbeeId}" ] + def cmds = [] + cmds << zigbee.setLevel(value) + cmds << "delay 1000" + cmds << zigbee.levelRefresh() + cmds } def refresh() { - getOnOff() + - getLevel() + - getTemperature() + - getPressure() + - getBattery() + zigbee.onOffRefresh() + + zigbee.levelRefresh() + + zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) + + zigbee.readAttribute(PRESSURE_MEASUREMENT_CLUSTER, 0x0020, [mfgCode: MFG_CODE]) + + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021) } /** * PING is used by Device-Watch in attempt to reach the Device * */ def ping() { - return refresh() + zigbee.levelRefresh() } def configure() { @@ -477,47 +160,13 @@ def configure() { // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - // get ZigBee ID by hidden tile because that's the only way we can do it - setZigBeeIdTile() - - def configCmds = [ - // bind reporting clusters to hub - //commenting out switch cluster bind as using wrapper onOffConfig of zigbee class - //"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500", - "zdo bind 0x${device.deviceNetworkId} 1 1 0x0008 {${device.zigbeeId}} {}", "delay 500", - "zdo bind 0x${device.deviceNetworkId} 1 1 0x0402 {${device.zigbeeId}} {}", "delay 500", - "zdo bind 0x${device.deviceNetworkId} 1 1 0x0403 {${device.zigbeeId}} {}", "delay 500", - "zdo bind 0x${device.deviceNetworkId} 1 1 0x0001 {${device.zigbeeId}} {}", "delay 500" - - // configure report commands - // zcl global send-me-a-report [cluster] [attr] [type] [min-interval] [max-interval] [min-change] - - // report with these parameters is preconfigured in firmware, can be overridden here - // vent on/off state - type: boolean, change: 1 - // "zcl global send-me-a-report 6 0 0x10 5 60 {01}", "delay 200", - // "send 0x${device.deviceNetworkId} 1 1", "delay 1500", - - // report with these parameters is preconfigured in firmware, can be overridden here - // vent level - type: int8u, change: 1 - // "zcl global send-me-a-report 8 0 0x20 5 60 {01}", "delay 200", - // "send 0x${device.deviceNetworkId} 1 1", "delay 1500", - - // report with these parameters is preconfigured in firmware, can be overridden here - // temperature - type: int16s, change: 0xA = 10 = 0.1C - // "zcl global send-me-a-report 0x0402 0 0x29 60 60 {0A00}", "delay 200", - // "send 0x${device.deviceNetworkId} 1 1", "delay 1500", - - // report with these parameters is preconfigured in firmware, can be overridden here - // keen home custom pressure (tenths of Pascals) - type: int32u, change: 1 = 0.1Pa - // "zcl mfg-code 0x115B", "delay 200", - // "zcl global send-me-a-report 0x0403 0x20 0x22 60 60 {010000}", "delay 200", - // "send 0x${device.deviceNetworkId} 1 1", "delay 1500", - - // report with these parameters is preconfigured in firmware, can be overridden here - // battery - type: int8u, change: 1 - // "zcl global send-me-a-report 1 0x21 0x20 60 3600 {01}", "delay 200", - // "send 0x${device.deviceNetworkId} 1 1", "delay 1500", + def cmds = [ + zigbee.temperatureConfig(30, 300) + + zigbee.onOffConfig() + + zigbee.addBinding(zigbee.LEVEL_CONTROL_CLUSTER) + + zigbee.addBinding(PRESSURE_MEASUREMENT_CLUSTER) + + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 600, 21600, 0x01) // battery precentage ] - return configCmds + zigbee.onOffConfig() + refresh() + return refresh() + delayBetween(cmds) } diff --git a/devicetypes/osotech/plantlink.src/plantlink.groovy b/devicetypes/osotech/plantlink.src/plantlink.groovy index 79cf20b982d..406f7425e51 100644 --- a/devicetypes/osotech/plantlink.src/plantlink.groovy +++ b/devicetypes/osotech/plantlink.src/plantlink.groovy @@ -36,7 +36,7 @@ metadata { attribute "linkBatteryLevel","string" attribute "installSmartApp","string" - fingerprint profileId: "0104", inClusters: "0000,0001,0B04" + fingerprint profileId: "0104", inClusters: "0000,0001,0B04", deviceJoinName: "Plant Link Humidity Sensor" } simulator { diff --git a/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy b/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy index df12e78fb15..5c49425e5c7 100644 --- a/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy +++ b/devicetypes/plaidsystems/spruce-controller.src/spruce-controller.groovy @@ -109,7 +109,7 @@ metadata { //ST release //fingerprint endpointId: '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18', profileId: '0104', deviceId: '0002', deviceVersion: '00', inClusters: '0000,0003,0004,0005,0006,000F', outClusters: '0003, 0019', manufacturer: 'PLAID SYSTEMS', model: 'PS-SPRZ16-01' //new release - fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,0009,000A,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01" + fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,0009,000A,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01", deviceJoinName: "Spruce Irrigation" } @@ -117,7 +117,7 @@ metadata { simulator { // status messages - // reply messages + // reply messages } preferences { @@ -483,7 +483,7 @@ def config(){ log.debug "Configuring Reporting and Bindings ${device.deviceNetworkId} ${device.zigbeeId}" def configCmds = [ - //program on/off + //program on/off "zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 1000", "zdo bind 0x${device.deviceNetworkId} 1 1 0x09 {${device.zigbeeId}} {}", "delay 1000", "zdo bind 0x${device.deviceNetworkId} 1 1 0x0F {${device.zigbeeId}} {}", "delay 1000", diff --git a/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy b/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy index 4e04f728c86..d8ff0f971e9 100644 --- a/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy +++ b/devicetypes/plaidsystems/spruce-sensor.src/spruce-sensor.groovy @@ -43,13 +43,13 @@ metadata { command "resetHumidity" command "refresh" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01", deviceJoinName: "Spruce Sensor" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP1", deviceJoinName: "Spruce Sensor" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP3", deviceJoinName: "Spruce Sensor" + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP1", deviceJoinName: "Spruce Irrigation" //Spruce Sensor + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP3", deviceJoinName: "Spruce Irrigation" //Spruce Sensor } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "-100..100", displayDuringSetup: false input "interval", "number", title: "Report Interval", description: "How often the device should report in minutes", range: "1..120", defaultValue: 10, displayDuringSetup: false input "resetMinMax", "bool", title: "Reset Humidity min and max", required: false, displayDuringSetup: false } @@ -155,7 +155,7 @@ private Map parseCatchAllMessage(String description) { sendEvent(name: 'configuration',value: configInterval, descriptionText: "Configuration Successful") //setConfig() log.debug "config complete" - //return resultMap = [name: 'configuration', value: configInterval, descriptionText: "Settings configured successfully"] + //return resultMap = [name: 'configuration', value: configInterval, descriptionText: "Settings configured successfully"] } else if (descMap.command == 0x0001){ def hexString = "${hex(descMap.data[5])}" + "${hex(descMap.data[4])}" @@ -258,9 +258,7 @@ private Map getTemperatureResult(value) { def linkText = getLinkText(device) if (tempOffset) { - def offset = tempOffset as int - def v = value as int - value = v + offset + value = new BigDecimal((value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } def descriptionText = "${linkText} is ${value}°${temperatureScale}" return [ diff --git a/devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy b/devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy new file mode 100644 index 00000000000..fef00c54bd2 --- /dev/null +++ b/devicetypes/qubino/qubino-3-phase-meter.src/qubino-3-phase-meter.groovy @@ -0,0 +1,195 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Qubino 3 Phase Meter", namespace: "qubino", author: "SmartThings", ocfDeviceType: "x.com.st.d.energymeter", mcdSync: true) { + capability "Energy Meter" + capability "Power Meter" + capability "Configuration" + capability "Sensor" + capability "Health Check" + capability "Refresh" + + fingerprint mfr: "0159", prod: "0007", model: "0054", deviceJoinName: "Qubino Energy Monitor" //Qubino 3 Phase Meter + // zw:L type:3103 mfr:0159 prod:0007 model:0054 ver:1.00 zwv:4.61 lib:03 cc:5E,55,86,73,56,98,9F,72,5A,70,60,85,8E,59,32,6C,7A epc:4 + } + + // tile definitions + tiles(scale: 2) { + multiAttributeTile(name:"power", type: "generic", width: 6, height: 4){ + tileAttribute("device.power", key: "PRIMARY_CONTROL") { + attributeState("default", label:'${currentValue} W') + } + tileAttribute("device.energy", key: "SECONDARY_CONTROL") { + attributeState("default", label:'${currentValue} kWh') + } + } + standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat",width: 2, height: 2) { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" + } + standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat",width: 2, height: 2) { + state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" + } + + main (["power","energy"]) + details(["power","energy","refresh", "configure"]) + } +} + +def installed() { + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + state.numberOfMeters = 3 + + if (!childDevices) { + addChildMeters(state.numberOfMeters) + } + + response(refresh()) +} + +def updated() { + response(refresh()) +} + +def ping() { + refresh() +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = createEvent(zwaveEvent(cmd)) + } + log.debug "Parse returned ${result?.descriptionText}" + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand(versions) + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + log.debug "Multichannel command ${cmd}" + (ep ? " from endpoint $ep" : "") + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, endpoint = null) { + handleMeterReport(cmd, endpoint) +} + +private handleMeterReport(cmd, endpoint) { + def event = createMeterEventMap(cmd) + if (endpoint && endpoint > 1) { + String childDni = "${device.deviceNetworkId}:${endpoint - 1}" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(event) + } else { + createEvent(event) + } +} + +private createMeterEventMap(cmd) { + def eventMap = [:] + if (cmd.scale == 0) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + } else if (cmd.scale == 2) { + eventMap.name = "power" + eventMap.value = Math.round(Math.abs(cmd.scaledMeterValue)) + eventMap.unit = "W" + } + eventMap +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + // Handles all Z-Wave commands we aren't interested in + log.warn "Not handled Z-Wave command: ${cmd}" + [:] +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +def refresh() { + delayBetween([ + encap(zwave.meterV3.meterGet(scale: 0)), + encap(zwave.meterV3.meterGet(scale: 2)) + ]) +} + +def configure() { + log.debug "configure() has been called" + encap(zwave.configurationV1.configurationSet(parameterNumber: 42, size: 2, scaledConfigurationValue: 1800)) // Report energy consumption every 30 minutes +} + +private addChildMeters(numberOfMeters) { + for (def endpoint : 1..numberOfMeters) { + try { + String childDni = "${device.deviceNetworkId}:$endpoint" + def componentLabel = device.displayName + " ${endpoint}" + addChildDevice("smartthings", "Child Energy Meter", childDni, device.getHub().getId(), [ + completedSetup : true, + label : componentLabel, + isComponent : true, + componentName : "endpointMeter$endpoint", + componentLabel : "Endpoint Meter $endpoint" + ]) + } catch (Exception e) { + log.warn "Exception: ${e}" + } + } +} + +private getMeterId(deviceNetworkId) { + def split = deviceNetworkId?.split(":") + return (split.length > 1) ? split[1] as Integer : null +} + +private childRefresh(deviceNetworkId) { + def meterId = getMeterId(deviceNetworkId) + if (switchId != null) { + sendHubCommand delayBetween([ + encap(zwave.meterV3.meterGet(scale: 0), meterId), + encap(zwave.meterV3.meterGet(scale: 2), meterId) + ]) + } +} \ No newline at end of file diff --git a/devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy b/devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy new file mode 100644 index 00000000000..6d3b34f82f3 --- /dev/null +++ b/devicetypes/qubino/qubino-dimmer.src/qubino-dimmer.groovy @@ -0,0 +1,652 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Qubino Dimmer", namespace: "qubino", author: "SmartThings", mnmn: "SmartThings", vid:"generic-dimmer-power-energy", ocfDeviceType: "oic.d.switch", runLocally: false, executeCommandsLocally: false) { + capability "Actuator" + capability "Configuration" + capability "Energy Meter" + capability "Health Check" + capability "Power Meter" + capability "Refresh" + capability "Sensor" + capability "Switch" + capability "Switch Level" + + // Qubino Flush Dimmer - ZMNHDD + // Raw Description zw:Ls type:1101 mfr:0159 prod:0001 model:0051 ver:3.08 zwv:4.38 lib:03 cc:5E,5A,73,98 sec:86,72,27,25,26,32,31,71,60,85,8E,59,70 secOut:26 role:05 ff:9C00 ui:9C00 epc:2 + fingerprint mfr: "0159", prod: "0001", model: "0051", deviceJoinName: "Qubino Dimmer" + + // Qubino DIN Dimmer + // Raw Description: zw:Ls type:1101 mfr:0159 prod:0001 model:0052 ver:3.01 zwv:4.24 lib:03 cc:5E,5A,73,98 sec:86,72,27,25,26,32,71,85,8E,59,70 secOut:26 role:05 ff:9C00 ui:9C00 + fingerprint mfr: "0159", prod: "0001", model: "0052", deviceJoinName: "Qubino Dimmer" + + // Qubino Flush Dimmer 0-10V - ZMNHVD + // Raw Description: zw:L type:1100 mfr:0159 prod:0001 model:0053 ver:2.04 zwv:4.34 lib:03 cc:5E,86,5A,72,73,27,25,26,85,8E,59,70 ccOut:20,26 role:05 ff:9C00 ui:9C00 + fingerprint mfr: "0159", prod: "0001", model: "0053", deviceJoinName: "Qubino Dimmer", mnmn: "SmartThings", vid:"generic-dimmer" + } + + tiles(scale: 2) { + multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + } + tileAttribute("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action: "switch level.setLevel" + } + } + + standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { + state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh" + } + + valueTile("level", "device.level", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "level", label: '${currentValue} %', unit: "%", backgroundColor: "#ffffff" + } + + valueTile("power", "device.power", width: 2, height: 2) { + state "default", label: '${currentValue} W' + } + valueTile("energy", "device.energy", width: 2, height: 2) { + state "default", label: '${currentValue} kWh' + } + + main(["switch"]) + details(["switch", "level", "power", "energy", "refresh"]) + } + + preferences { + // Preferences template begin + parameterMap.each { + input ( + title: it.name, description: it.description, type: "paragraph", element: "paragraph" + ) + + switch(it.type) { + case "boolean": + input( + type: "paragraph", element: "paragraph", + description: "Option enabled: ${it.activeDescription}\n" + + "Option disabled: ${it.inactiveDescription}" + ) + input( + name: it.key, type: "bool", title: "Enable", required: false, + defaultValue: it.defaultValue == it.activeOption + ) + break + case "enum": + input( + name: it.key, title: "Select", type: "enum", required: false, options: it.values, + defaultValue: it.defaultValue + ) + break + case "range": + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", range: it.range, required: false, + defaultValue: it.defaultValue + ) + break + } + } + // Preferences template end + } +} + +//Globals, input types used in sevice settings (parameter #1: Input 1 switch type) +private getINPUT_TYPE_MONO_STABLE_SWITCH() {0} +private getINPUT_TYPE_BI_STABLE_SWITCH() {1} +private getINPUT_TYPE_POTENTIOMETER() {2} +private getINPUT_TYPE_TEMPERATURE_SENSOR() {3} + +def installed() { + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + state.currentPreferencesState."$it.key".status = "synced" + } + // Preferences template end +} + +def updated() { +// Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it) && !excludeParameterFromSync(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + } else if (state.currentPreferencesState."$it.key".value == null) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end +} + +def excludeParameterFromSync(preference){ + def exclude = false + if (preference.key == "input1SwitchType") { + // Only Flush Dimmer 0-10V supports all input types: + // 0 - MONO_STABLE_SWITCH, + // 1 - BI_STABLE_SWITCH, + // 2 - TYPE_POTENTIOMETER, + // 3 - TEMPERATURE_SENSO. + if (supportsMonoAndBiStableSwitchOnly() && (preference.value == INPUT_TYPE_POTENTIOMETER || preference.value == INPUT_TYPE_TEMPERATURE_SENSOR)){ + exclude = true + } + } else if (preference.key == "inputsSwitchTypes" || preference.key == "enable/DisableAdditionalSwitch") { + // Only Flush Dimmer supports this parameter + if (isDINDimmer() || isFlushDimmer010V()) { + exclude = true + } + } + + if (exclude) { + log.warn "Preference no ${preference.parameterNumber} - ${preference.key} is not supported by this device" + } + return exclude +} + +private getReadConfigurationFromTheDeviceCommands() { + def commands = [] + parameterMap.each { + state.currentPreferencesState."$it.key".status = "reverseSyncPending" + commands += zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber) + } + commands +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size) + commands += zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size) + commands += zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber) + } + } + sendHubCommand(encapCommands(commands)) +} + +def configure() { + def commands = [] + log.debug "configure" + /* + Association Groups: + + Flush Dimmer: + + Group 1: Lifeline group (reserved for communication with the hub). + Group 2: BasicSetKey1 (status change report for I1 input), up to 16 nodes. + Group 3: DimmerStartStopKey1 (status change report for I1 input), up to 16 nodes. + Group 4: DimmerSetKey1 (status change report of the Flush Dimmer) up to 16 nodes + Group 5: BasicSetKey2 (status change report for I2 input) up to 16 nodes. + Group 6: NotificationKey2 (status change report for I2 input) up to 16 nodes. + + Flush Dimmer 0-10V: + + Group 1: Lifeline group (reserved for communication with the hub) + Group 2: Basic on/off (status change report for the input) + Group 3: Start level change/stop (status change report for the input). + Working only when the Parameter no. 1 is set to mono stable switch type. + Group 4: Multilevel set (status change report of dimmer). Working only when the Parameter no. 1 is set to mono stable switch type. + Group 5: Multilevel sensor report (status change report of the analogue sensor). + Group 6: Multilevel sensor report (status change report of the temperature sensor) + + + Qubino DIN Dimmer: + + Group 1: Lifeline group (reserved for communication with the hub). + Group 2: Basic on/off (status change report for output), up to 16 nodes. + Group 3: Start level change/stop (status change report for I1 input). + Group 4: Multilevel set (status change report of the output). + Group 5: Multilevel sensor report (external temperature sensor report). + + */ + commands << zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]) + commands << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]) + commands << zwave.associationV1.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]) + commands << zwave.associationV1.associationSet(groupingIdentifier:4, nodeId:[zwaveHubNodeId]) + commands << zwave.associationV1.associationSet(groupingIdentifier:5, nodeId:[zwaveHubNodeId]) + commands << zwave.associationV1.associationSet(groupingIdentifier:6, nodeId:[zwaveHubNodeId]) + commands << zwave.multiChannelV3.multiChannelEndPointGet() + commands += getRefreshCommands() + + // 1% is default Minimum dimming value for dimmers, + // when device is set to 1% - it turns off and device does not send any level reports + // Minimum dimming value has to be set to 2%, so the device's internal range would be 2-100% + // Still, for users it will relatively be 1-100% on the UI and device will report it. + // Parameter no. 60 – Minimum dimming value + commands << zwave.configurationV2.configurationSet(scaledConfigurationValue: 2, parameterNumber: 60, size: 1) + commands += getReadConfigurationFromTheDeviceCommands() + + encapCommands(commands) +} + +def parse(String description) { + log.debug "parse() / description: ${description}" + + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } + + log.debug "Parse returned ${result}" + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + + if(state.currentPreferencesState."$key".status == "reverseSyncPending"){ + log.debug "reverseSyncPending" + state.currentPreferencesState."$key".value = preferenceValue + state.currentPreferencesState."$key".status = "synced" + } else { + def preferenceKey = preference.key + def settingsKey = settings."$key" + log.debug "preference.key: ${preferenceKey}" + log.debug "settings.key: ${settingsKey}" + log.debug "preferenceValue: ${preferenceValue}" + + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + } + // Preferences template end +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "boolean": + return settings."$parameterKey" ? preference.optionActive : preference.optionInactive + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isPreferenceChanged(preference) { + if (settings."$preference.key" != null) { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } else { + return false + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + log.debug "Multichannel command ${cmd}" + (ep ? " from endpoint $ep" : "") + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + // Handles other Z-Wave commands that are not supported here + log.debug "Command: ${cmd}" + [:] +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + log.debug "BasicReport: ${cmd}" + if(isDINDimmer()) { + sendHubCommand(encap(zwave.meterV2.meterGet(scale: 0))) + sendHubCommand(encap(zwave.meterV2.meterGet(scale: 2))) + } + dimmerEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd, ep = null) { + log.debug "BasicSet: ${cmd}" + def input1SwitchType = Integer.parseInt(state.currentPreferencesState.input1SwitchType.value) + + if(input1SwitchType == INPUT_TYPE_POTENTIOMETER) { + log.debug "BasicSet: ${cmd} / INPUT_TYPE_POTENTfIOMETER" + sendHubCommand(encap(zwave.switchMultilevelV3.switchMultilevelGet())) + } else if (input1SwitchType == INPUT_TYPE_BI_STABLE_SWITCH) { + log.debug "BasicSet: ${cmd} / INPUT_TYPE_BI_STABLE_SWITCH" + dimmerEvents(cmd) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd, ep = null) { + log.debug "SwitchMultilevelReport: ${cmd}" + dimmerEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelSet cmd, ep = null) { + log.debug "SwitchMultilevelSet: ${cmd}" + dimmerEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, ep = null) { + log.debug "MeterReport: ${cmd}" + handleMeterReport(cmd) +} + +def handleMeterReport(cmd) { + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + log.debug("createEvent energy") + createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kWh") + } else if (cmd.scale == 1) { + log.debug("createEvent energy kVAh") + createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kVAh") + } else if (cmd.scale == 2) { + log.debug("createEvent power") + createEvent(name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W") + } + } +} + +private dimmerEvents(physicalgraph.zwave.Command cmd, ep = null) { + def cmdValue = cmd.value + def value = (cmdValue ? "on" : "off") + def result = [createEvent(name: "switch", value: value)] + if (cmdValue && cmdValue <= 100) { + result << createEvent(name: "level", value: cmdValue == 99 ? 100 : cmdValue) + } + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd, ep = null) { + log.info "SensorMultilevelReport: ${cmd}, endpoint: ${ep}" + def result = [] + + def map = [:] + switch (cmd.sensorType) { + case 1: + map.name = "temperature" + def cmdScale = cmd.scale == 1 ? "F" : "C" + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) + map.unit = getTemperatureScale() + break + default: + map.descriptionText = cmd.toString() + } + log.debug "SensorMultilevelReport, ${map}, ${map.name}, ${map.value}, ${map.unit}" + handleChildEvent(map) + result << createEvent(map) +} + +def handleChildEvent(map) { + def childDni = "${device.deviceNetworkId}:" + 2 + log.debug "handleChildEvent / find child device: ${childDni}" + def childDevice = childDevices.find { it.deviceNetworkId == childDni } + + if(!childDevice) { + log.debug "handleChildEvent / creating a child device" + childDevice = createChildDevice( + "qubino", + "Qubino Temperature Sensor", + childDni, + "Qubino Temperature Sensor" + ) + } + log.debug "handleChildEvent / sending event: ${map} to child: ${childDevice}" + childDevice?.sendEvent(map) +} + +def createChildDevice(childDthNamespace, childDthName, childDni, childComponentLabel) { + try { + log.debug "Creating a child device: ${childDthNamespace}, ${childDthName}, ${childDni}, ${childComponentLabel}" + def childDevice = addChildDevice(childDthNamespace, childDthName, childDni, device.hub.id, + [ + completedSetup: true, + label: childComponentLabel, + isComponent: false + ]) + log.debug "createChildDevice: ${childDevice}" + childDevice + } catch(Exception e) { + log.debug "Exception: ${e}" + } +} + +def on() { + def commands = [ + zwave.switchMultilevelV3.switchMultilevelSet(value: 0xFF, dimmingDuration: 0x00), + zwave.switchMultilevelV3.switchMultilevelGet() + ] + + if(supportsPowerMeter()){ + commands << zwave.meterV2.meterGet(scale: 0) + commands << zwave.meterV2.meterGet(scale: 2) + } + + encapCommands(commands, 3000) +} + +def off() { + def commands = [ + zwave.switchMultilevelV3.switchMultilevelSet(value: 0x00, dimmingDuration: 0x00), + zwave.switchMultilevelV3.switchMultilevelGet() + ] + + if(supportsPowerMeter()){ + commands << zwave.meterV2.meterGet(scale: 0) + commands << zwave.meterV2.meterGet(scale: 2) + } + + encapCommands(commands, 3000) +} + +def setLevel(value, duration = null) { + log.debug "setLevel >> value: $value, duration: $duration" + def valueaux = value as Integer + def level = Math.max(Math.min(valueaux, 99), 0) + def getStatusDelay = 3000 + def dimmingDuration + + def commands = [] + + if(duration == null) { + dimmingDuration = 0 + } else { + dimmingDuration = duration < 128 ? duration : 128 + Math.round(duration / 60) + getStatusDelay = duration < 128 ? (duration * 1000) + 2000 : (Math.round(duration / 60) * 60 * 1000) + 2000 + } + + commands << zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration) + commands << zwave.switchMultilevelV3.switchMultilevelGet() + + if(supportsPowerMeter()){ + commands << zwave.meterV2.meterGet(scale: 0) + commands << zwave.meterV2.meterGet(scale: 2) + } + + encapCommands(commands, getStatusDelay) +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + refresh() +} + +def refresh() { + log.debug "refresh" + refreshChild() + encapCommands(getRefreshCommands()) +} + +def getRefreshCommands() { + def commands = [] + commands << zwave.basicV1.basicGet() + + if(isFlushDimmer() || isDINDimmer()) { + commands << zwave.meterV2.meterGet(scale: 0) + commands << zwave.meterV2.meterGet(scale: 2) + } + commands +} + +private refreshChild() { + // refresh a child temperature sensor (if available) + if(childDevices){ + def childDni = "${device.deviceNetworkId}:2" + def childDevice = childDevices.find { it.deviceNetworkId == childDni } + + if (childDevice != null) { + sendHubCommand(encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))) + } + } +} + +private encapCommands(commands, delay=200) { + if (commands.size() > 0) { + delayBetween(commands.collect{ encap(it) }, delay) + } else { + [] + } +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + + if (zwaveInfo.zw.endsWith("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private supportsMonoAndBiStableSwitchOnly() { + return isDINDimmer() || isFlushDimmer() +} + +private supportsPowerMeter() { + return isDINDimmer() || isFlushDimmer() +} + +private isFlushDimmer(){ + zwaveInfo.mfr.equals("0159") && zwaveInfo.model.equals("0051") +} + +private isDINDimmer(){ + zwaveInfo.mfr.equals("0159") && zwaveInfo.model.equals("0052") +} + +private isFlushDimmer010V(){ + zwaveInfo.mfr.equals("0159") && zwaveInfo.model.equals("0053") +} + +private getParameterMap() {[ + [ + name: "Input 1 switch type", key: "input1SwitchType", type: "enum", + parameterNumber: 1, size: 1, defaultValue: 0, + values: [ + 0: "Default value - Mono-stable switch type (push button) – button quick press turns between previous set dimmer value and zero)", + 1: "Bi-stable switch type (on/off toggle switch)", + 2: "Potentiometer (applies to Flush Dimmer 0-10V only, dimmer is using set value the last received from potentiometer or from z-wave controller)" + ], + description: "Set input based on device type (mono-stable switch, bi-stable switch, potentiometer)." + ], + [ + name: "Input 2 switch type (applies to Qubino Flush Dimmer only)", key: "inputsSwitchTypes", type: "enum", + parameterNumber: 2, size: 1, defaultValue: 0, + values: [ + 0: "Default value - Mono-stable switch type (push button) – button quick press turns between previous set dimmer value and zero)", + 1: "Bi-stable switch type (on/off toggle switch)" + ], + description: "Select between push-button (momentary) and on/off toggle switch types. Both inputs must work the same way." + ], + [ + name: "Enable/Disable the 3-way switch/additional switch (applies to Qubino Flush Dimmer only)", key: "enable/DisableAdditionalSwitch", type: "enum", + parameterNumber: 20, size: 1, defaultValue: 0, + values: [ + 0: "Default value - single push-button (connected to l1)", + 1: "3-way switch (connected to l1 and l2)", + 2: "additional switch (connected to l2)", + ], + description: "Dimming is done by using a push-button or a switch, connected to l1 (by default). If the 3-way switch option is set, dimming can be controlled by a push-button or a switch connected to l1 and l2." + ], + [ + name: "Enable/Disable Double click function", key: "enable/DisableDoubleClickFunction", type: "boolean", + parameterNumber: 21, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "Default value - Double click disabled", + optionActive: 1, activeDescription: "Double click enabled", + description: "If enabled, a fast double-click on the push button will set the dimming level to its max. " + + "Valid only if input is set as mono-stable (push button)." + ], + [ + name: "Saving the state of the device after a power failure", key: "savingTheStateOfTheDeviceAfterAPowerFailure", type: "boolean", + parameterNumber: 30, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "Default value - dimmer module saves its state before power failure (it returns to the last position saved before a power failure)", + optionActive: 1, activeDescription: " Flush Dimmer 0-10V module does not save the state after a power failure, it returns to off position", + description: "Set whether the device stores or does not store the last output level in the event of a power outage." + ], + [ + name: "Dimming time (soft on/off)", key: "dimmingTime(SoftOn/Off)", type: "range", + parameterNumber: 65, size: 2, defaultValue: 100, + range: "50..255", + description: "The time it takes for the dimmer to transition between min and max brightness after a short press of the button or when controlled through the UI" + + "100 (Default value) = 1s, " + + "50 - 255 = 500 - 2550 milliseconds (2,55s), step is 10 milliseconds" + ], + [ + name: "Dimming time when key pressed", key: "dimmingTimeWhenKeyPressed", type: "range", + parameterNumber: 66, size: 2, defaultValue: 3, + range: "1..255", + description: "The time it takes for the dimmer to transition between min and max brightness when push button I1 or other associated device is held continuously" + + "3 seconds (Default value), " + + "1 - 255 seconds" + ], + [ + name: "Dimming duration", key: "dimmingDuration", type: "range", + parameterNumber: 68, size: 1, defaultValue: 0, + range: "0..127", + description: "The Duration field MUST specify the time that the transition should take from the current value to the new target value. " + + "A supporting device SHOULD respect the specified Duration value. " + + "0 (Default value) - dimming duration according to parameter: 'Dimming time when key pressed'," + + "1 to 127 seconds" + ] +]} \ No newline at end of file diff --git a/devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy b/devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy new file mode 100644 index 00000000000..2f2a66ca2df --- /dev/null +++ b/devicetypes/qubino/qubino-flush-2-relay.src/qubino-flush-2-relay.groovy @@ -0,0 +1,480 @@ +/** + * Copyright 2020 SRPOL + * + * 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: "Qubino Flush 2 Relay", namespace: "qubino", author: "SmartThings", mnmn: "SmartThings", vid: "generic-switch-power-energy") { + capability "Switch" + capability "Power Meter" + capability "Energy Meter" + capability "Refresh" + capability "Actuator" + capability "Sensor" + capability "Health Check" + + command "reset" + + fingerprint mfr: "0159", prod: "0002", model: "0051", deviceJoinName: "Qubino Switch 1" //Qubino Flush 2 Relay + fingerprint mfr: "0159", prod: "0002", model: "0052", deviceJoinName: "Qubino Switch" //Qubino Flush 1 Relay + fingerprint mfr: "0159", prod: "0002", model: "0053", deviceJoinName: "Qubino Switch", mnmn: "SmartThings", vid: "generic-switch" //Qubino Flush 1D Relay + } + + tiles(scale: 2) { + multiAttributeTile(name:"switch", type: "generic", width: 6, height: 4, canChangeIcon: true){ + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState("on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc") + attributeState("off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff") + } + } + valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} W' + } + valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} kWh' + } + standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" + } + standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'reset kWh', action:"reset" + } + + main(["switch"]) + details(["switch","power","energy","refresh","reset"]) + } + + preferences { + parameterMap.each { + input (title: it.name, description: it.description, type: "paragraph", element: "paragraph") + + switch(it.type) { + case "boolean": + input(type: "paragraph", element: "paragraph", description: "Option enabled: ${it.activeDescription}\n" + + "Option disabled: ${it.inactiveDescription}" + ) + input(name: it.key, type: "boolean", title: "Enable", defaultValue: it.defaultValue == it.activeOption, required: false) + break + case "enum": + input(name: it.key, title: "Select", type: "enum", options: it.values, defaultValue: it.defaultValue, required: false) + break + } + } + } +} + +def installed() { + if (zwaveInfo?.model.equals("0051")) { + state.numberOfSwitches = 2 + } else { + state.numberOfSwitches = 1 + } + + if (!childDevices && state.numberOfSwitches > 1) { + addChildSwitches(state.numberOfSwitches) + } + + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + def preferenceName = it.key + "Boolean" + settings."$preferenceName" = true + state.currentPreferencesState."$it.key".status = "synced" + } + // Preferences template end + response([ + refresh((1..state.numberOfSwitches).toList()) + ]) +} + +def updated() { + if (!childDevices && state.numberOfSwitches > 1) { + addChildSwitches(state.numberOfSwitches) + } + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it) && !excludeParameterFromSync(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + } else if (!state.currentPreferencesState."$it.key".value) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end +} + +def excludeParameterFromSync(preference){ + def exclude = false + if (preference.key == "outputQ2SwitchSelection") { + if (zwaveInfo?.model?.equals("0052") || zwaveInfo?.model?.equals("0053")) { + exclude = true + } + } + + if (exclude) { + log.warn "Preference no ${preference.parameterNumber} - ${preference.key} is not supported by this device" + } + return exclude +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + try { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } catch (e) { + log.warn "There's been an issue with preference: ${it.key}" + } + } + sendHubCommand(commands) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd, ep = null) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + // Preferences template end +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "boolean": + return settings."$parameterKey" ? preference.optionActive : preference.optionInactive + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isPreferenceChanged(preference) { + if (settings."$preference.key" != null) { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } else { + return false + } +} + +def parse(String description) { + def result = null + if (description.startsWith("Err")) { + result = createEvent(descriptionText:description, isStateChange:true) + } else if (description != "updated") { + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } + } + log.debug "parsed '${description}' to ${result.inspect()}" + result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd, ep = null) { + log.debug "Security Message Encap ${cmd}" + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand, null) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + log.debug "Multichannel command ${cmd}" + (ep ? " from endpoint $ep" : "") + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + log.debug "Basic ${cmd}" + (ep ? " from endpoint $ep" : "") + changeSwitch(ep, cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) { + log.debug "Binary ${cmd}" + (ep ? " from endpoint $ep" : "") + changeSwitch(ep, cmd) +} + +private changeSwitch(endpoint, cmd) { + def value = cmd.value ? "on" : "off" + if (endpoint == 1) { + createEvent(name: "switch", value: value, isStateChange: true, descriptionText: "Switch ${endpoint} is ${value}") + } else if (endpoint) { + String childDni = "${device.deviceNetworkId}:$endpoint" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(name: "switch", value: value, isStateChange: true, descriptionText: "Switch ${endpoint} is ${value}") + } +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, ep = null) { + log.debug "Meter ${cmd}" + (ep ? " from endpoint $ep" : "") + if (ep == 1) { + [ + createEvent(createMeterEventMap(cmd)), + response(encap(zwave.meterV3.meterGet(scale: 0x00), 1)) + ] + } else if (ep) { + String childDni = "${device.deviceNetworkId}:$ep" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(createMeterEventMap(cmd)) + response(encap(zwave.meterV3.meterGet(scale: 0x00), ep)) + } +} + +private createMeterEventMap(cmd) { + def eventMap = [:] + if (cmd.meterType == 1) { + if (cmd.scale == 0) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + } else if (cmd.scale == 2) { + eventMap.name = "power" + eventMap.value = Math.round(cmd.scaledMeterValue) + eventMap.unit = "W" + } + } + eventMap +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd, ep = null) { + log.debug "SensorMultilevelReport ${cmd}" + (ep ? " from endpoint $ep" : "") + def result = [] + + def map = [:] + switch (cmd.sensorType) { + case 1: + map.name = "temperature" + def cmdScale = cmd.scale == 1 ? "F" : "C" + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) + map.unit = getTemperatureScale() + break + default: + map.descriptionText = cmd.toString() + } + def child = childDevices.find { it.deviceNetworkId == state.temperatureSensorDni } + if (!child) { + child = addChildTemperatureSensor() + } + child?.sendEvent(map) + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, ep) { + log.warn "Unhandled ${cmd}" + (ep ? " from endpoint $ep" : "") +} + +def on() { + onOffCmd(0xFF) +} + +def off() { + onOffCmd(0x00) +} + +def ping() { + refresh() +} + +def childOnOff(deviceNetworkId, value) { + def switchId = getSwitchId(deviceNetworkId) + if (switchId != null) sendHubCommand onOffCmd(value, switchId) +} + +private onOffCmd(value, endpoint = 1) { + delayBetween([ + encap(zwave.basicV1.basicSet(value: value), endpoint), + encap(zwave.basicV1.basicGet(), endpoint), + ]) +} + +def childRefresh(deviceNetworkId, includeMeterGet = true) { + def switchId = getSwitchId(deviceNetworkId) + if (switchId != null) { + sendHubCommand refresh([switchId],includeMeterGet) + } +} + +def refresh(endpoints = [1], includeMeterGet = true) { + + def cmds = [] + + endpoints.each { + cmds << [encap(zwave.basicV1.basicGet(), it)] + if (includeMeterGet) { + cmds << encap(zwave.meterV3.meterGet(scale: 0), it) + cmds << encap(zwave.meterV3.meterGet(scale: 2), it) + } + } + + delayBetween(cmds, 200) +} + +private resetAll() { + childDevices.each { + if (it.deviceNetworkId != state.temperatureSensorDni) { + childReset(it.deviceNetworkId) + } + } + sendHubCommand reset() +} + +def childReset(deviceNetworkId) { + def switchId = getSwitchId(deviceNetworkId) + if (switchId != null) { + log.debug "Child reset switchId: ${switchId}" + sendHubCommand reset(switchId) + } +} + +def reset(endpoint = 1) { + log.debug "Resetting endpoint: ${endpoint}" + delayBetween([ + encap(zwave.meterV3.meterReset(), endpoint), + encap(zwave.meterV3.meterGet(scale: 0), endpoint), + "delay 500" + ], 500) +} + +def getSwitchId(deviceNetworkId) { + def split = deviceNetworkId?.split(":") + return (split.length > 1) ? split[1] as Integer : null +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private addChildSwitches(numberOfSwitches) { + for (def endpoint : 2..numberOfSwitches) { + try { + String childDni = "${device.deviceNetworkId}:$endpoint" + def componentLabel = device.displayName[0..-2] + "${endpoint}" + addChildDevice("smartthings", "Child Metering Switch", childDni, device.getHub().getId(), [ + completedSetup : true, + label : componentLabel, + isComponent : false + ]) + } catch(Exception e) { + log.warn "Exception: ${e}" + } + } +} + +private addChildTemperatureSensor() { + try { + String childDni = "${device.deviceNetworkId}:${state.numberOfSwitches + 1}" + state.temperatureSensorDni = childDni + def childDevice = addChildDevice("qubino", "Qubino Temperature Sensor", childDni, device.getHub().getId(), [ + completedSetup : true, + label : "Qubino Temperature Sensor", + isComponent : false + ]) + childDevice + } catch(Exception e) { + log.warn "Exception: ${e}" + } +} + +private getParameterMap() {[ + [ + name: "Input 1 switch type", key: "input1SwitchType", type: "enum", + parameterNumber: 1, size: 1, defaultValue: 1, + values: [ + 0: "Mono-stable switch type (push button)", + 1: "Bi-stable switch type", + ], + description: "Input 1 switch type" + ], + [ + name: "Input 2 switch type", key: "input2SwitchType", type: "enum", + parameterNumber: 2, size: 1, defaultValue: 1, + values: [ + 0: "Mono-stable switch type (push button)", + 1: "Bi-stable switch type", + ], + description: "Input 2 switch type" + ], + [ + name: "Saving the state of the relays Q1 and Q2 after a power failure", key: "savingTheStateOfTheRelaysQ1AndQ2AfterAPowerFailure", type: "boolean", + parameterNumber: 30, size: 1, defaultValue: 0, + optionInactive: 0, inactiveDescription: "State is saved and brought back after a power failure", + optionActive: 1, activeDescription: "State is not saved, outputs will be off after a power failure", + description: "Saving the state of the relays Q1 and Q2 after a power failure" + ], + [ + name: "Output Q1 Switch selection", key: "outputQ1SwitchSelection", type: "enum", + parameterNumber: 63, size: 1, defaultValue: 0, + values: [ + 0: "When system is turned off the output is 0V (NC).", + 1: "When system is turned off the output is 230V (NO).", + ], + description: "Set value means the type of the device that is connected to the Q1 output. The device type can be normally open (NO) or normally close (NC). " + ], + [ + name: "Output Q2 Switch selection", key: "outputQ2SwitchSelection", type: "enum", + parameterNumber: 64, size: 1, defaultValue: 0, + values: [ + 0: "When system is turned off the output is 0V (NC).", + 1: "When system is turned off the output is 230V (NO).", + ], + description: "(Only for Qubino Flush 2 Relay) Set value means the type of the device that is connected to the Q2 output. The device type can be normally open (NO) or normally close (NC). " + ] +]} \ No newline at end of file diff --git a/devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy b/devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy new file mode 100644 index 00000000000..13845b2c378 --- /dev/null +++ b/devicetypes/qubino/qubino-flush-shutter.src/qubino-flush-shutter.groovy @@ -0,0 +1,501 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Qubino Flush Shutter", namespace: "qubino", author: "SmartThings", ocfDeviceType: "oic.d.blind", mcdSync: true) { + capability "Window Shade" + capability "Window Shade Level" + capability "Power Meter" + capability "Energy Meter" + capability "Refresh" + capability "Health Check" + capability "Configuration" + + //zw:L type:1107 mfr:0159 prod:0003 model:0052 ver:1.01 zwv:4.05 lib:03 cc:5E,86,72,5A,73,20,27,25,26,32,60,85,8E,59,70 ccOut:20,26 epc:2 + fingerprint mfr: "0159", prod: "0003", model: "0052", deviceJoinName: "Qubino Window Treatment" // Qubino Flush Shutter (110-230 VAC) + //zw:L type:1107 mfr:0159 prod:0003 model:0053 ver:1.01 zwv:4.05 lib:03 cc:5E,86,72,5A,73,20,27,25,26,32,85,8E,59,70 ccOut:20,26 + fingerprint mfr: "0159", prod: "0003", model: "0053", deviceJoinName: "Qubino Window Treatment" // Qubino Flush Shutter DC + } + + tiles(scale: 2) { + multiAttributeTile(name:"windowShade", type: "generic", width: 6, height: 4) { + tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") { + attributeState "open", label: 'Open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing" + attributeState "closed", label: 'Closed', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening" + attributeState "partially open", label: 'Partially open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#d45614", nextState: "closing" + attributeState "opening", label: 'Opening', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "partially open" + attributeState "closing", label: 'Closing', action: "pause", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "partially open" + } + } + valueTile("shadeLevel", "device.level", width: 4, height: 1) { + state "shadeLevel", label: 'Shade is ${currentValue}% up', defaultState: true + } + controlTile("levelSliderControl", "device.level", "slider", width:2, height: 1, inactiveLabel: false) { + state "shadeLevel", action:"switch level.setLevel" + } + valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} W' + } + valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} kWh' + } + standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" + } + + main "windowShade" + details(["windowShade", "shadeLevel", "levelSliderControl", "power", "energy", "refresh"]) + } + + preferences { + parameterMap.each { + input (title: it.name, description: it.description, type: "paragraph", element: "paragraph") + + switch (it.type) { + case "enum": + input(name: it.key, title: "Select", type: "enum", options: it.values, defaultValue: it.defaultValue, required: false) + break + case "range": + input(name: it.key, type: "number", title: "Set value (range ${it.range})", defaultValue: it.defaultValue, range: it.range, required: false) + break + } + } + } +} + +def installed() { + state.currentMode = null + state.childDevices = [:] + state.venetianBlindDni = null + state.temperatureSensorDni = null + sendHubCommand(encap(zwave.configurationV2.configurationGet(parameterNumber: 71))) + sendEvent(name: "checkInterval", value: 2 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + def preferenceName = it.key + "Boolean" + settings."$preferenceName" = true + state.currentPreferencesState."$it.key".status = "synced" + } + // Preferences template end + sendEvent(name: "supportedWindowShadeCommands", value: ["open", "close", "pause"]) +} + +def updated() { + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + } else if (!state.currentPreferencesState."$it.key".value) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end +} + +private syncConfiguration() { + def commands = [] + parameterMap.each { + try { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } catch (e) { + log.warn "There's been an issue with preference: ${it.key}" + } + } + sendHubCommand(commands) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find( {it.parameterNumber == cmd.parameterNumber} ) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + if (settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + handleConfigurationChange(cmd) + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + // Preferences template end + handleConfigurationChange(cmd) +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + switch (preference.type) { + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isPreferenceChanged(preference) { + if (settings."$preference.key" != null) { + def value = state.currentPreferencesState."$preference.key" + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } else { + return false + } +} + +def handleConfigurationChange(confgurationReport) { + switch (confgurationReport.parameterNumber) { + case 71: //Operating mode + switch (confgurationReport.scaledConfigurationValue) { + case 0: // Shutter + checkAndTriggerModeChange("windowShade") + break + case 1: // Venetian + checkAndTriggerModeChange("windowShadeVenetian") + break + } + log.info "Current device's mode is: ${state.currentMode}" + break + case 72: + state.timeOfVenetianMovement = confgurationReport.scaledConfigurationValue + break + default: + log.info "Parameter no. ${confgurationReport.parameterNumber} has no specific handler" + break + } +} + +private checkAndTriggerModeChange(reportedMode) { + if (state.currentMode != reportedMode) { + state.currentMode = reportedMode + createVenetianBlindsChildDeviceIfNeeded() + } +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } else { + log.warn "${device.displayName} - no-parsed event: ${description}" + } + log.debug "Parse returned: ${result}" + return result +} + +def multilevelChildInstalled(childDni) { + state.timeOfVenetianMovement = 150 + sendHubCommand(encap(zwave.switchMultilevelV3.switchMultilevelGet(), 2)) +} + +def close() { + setShadeLevel(0x64) +} + +def open() { + setShadeLevel(0x00) +} + +def pause() { + def currentShadeState = device.currentState("windowShade").value + if (currentShadeState == "opening" || currentShadeState == "closing") { + encap(zwave.switchMultilevelV3.switchMultilevelStopLevelChange()) + } else { + encap(zwave.switchMultilevelV3.switchMultilevelGet()) + } +} + +def setLevelChild(level, childDni) { + setSlats(level) +} + +def setLevel(level) { + setShadeLevel(level) +} + +def setShadeLevel(level) { + log.debug "Setting shade level: ${level}" + encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level))) +} + +def setSlats(level) { + def time = (int) (state.timeOfVenetianMovement * 1.1) + sendHubCommand([ + encap(zwave.switchMultilevelV3.switchMultilevelSet(value: Math.min(0x63, level)), 2), + "delay ${time}", + encap(zwave.switchMultilevelV3.switchMultilevelGet(), 2) + ]) +} + +def refresh() { + [ + encap(zwave.switchMultilevelV3.switchMultilevelGet()), + encap(zwave.meterV3.meterGet(scale: 0x00)), + ] +} + +def ping() { + response(refresh()) +} + +def configure() { + def configurationCommands = [] + configurationCommands += encap(zwave.associationV1.associationSet(groupingIdentifier: 7, nodeId: [zwaveHubNodeId])) + configurationCommands += encap(zwave.meterV3.meterGet(scale: 0x00)) + configurationCommands += encap(zwave.meterV3.meterGet(scale: 0x02)) + configurationCommands += encap(zwave.switchMultilevelV3.switchMultilevelGet()) + configurationCommands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: 1, parameterNumber: 40, size: 1)) + + delayBetween(configurationCommands) +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "unable to extract secure command from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { + def encapsulatedCommand = cmd.encapsulatedCommand() + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd, ep = null) { + log.debug "SwitchMultilevelReport ${cmd} from endpoint: ${ep}" + if (cmd.value != 0xFE) { + if (ep != 2) { + shadeEvent(cmd.value) + } else { + def event = [name: "level", value: cmd.value != 0x63 ? cmd.value : 100] + sendEventsToVenetianBlind([event]) + } + } else { + log.warn "Something went wrong with calibration, position of blind is unknown" + if (ep == 2) { + sendEventsToVenetianBlind([[name: "level", value: 0]]) + } else { + [ + createEvent([name: "windowShade", value: "unknown"]), + createEvent([name: "shadeLevel", value: 0]) + ] + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelSet cmd, ep = null) { + def currentLevel = Integer.parseInt(device.currentState("shadeLevel").value) + state.blindsLastCommand = currentLevel > cmd.value ? "opening" : "closing" + state.shadeTarget = cmd.value + sendHubCommand(encap(zwave.meterV3.meterGet(scale: 0x02))) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) { + log.debug "BasicReport ${cmd}" + if (cmd.value != 0xFE && ep != 2) { + shadeEvent(cmd.value) + } else { + log.warn "Something went wrong with calibration, position of blind is unknown" + } +} + +private shadeEvent(value) { + def shadeValue + def events = [] + if (!value) { + shadeValue = "open" + } else if (value == 0x63) { + shadeValue = "closed" + } else { + shadeValue = "partially open" + } + events += createEvent([name: "windowShade", value: shadeValue]) + events += createEvent([name: "shadeLevel", value: value != 0x63 ? value : 100]) + + events +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd, ep = null) { + def events = [] + if (cmd.meterType == 0x01) { + def eventMap = [:] + if (cmd.scale == 0x00) { + eventMap.name = "energy" + eventMap.value = cmd.scaledMeterValue + eventMap.unit = "kWh" + events += createEvent(eventMap) + } else if (cmd.scale == 0x02) { + eventMap.name = "power" + eventMap.value = Math.round(cmd.scaledMeterValue) + eventMap.unit = "W" + events += createEvent(eventMap) + if (Math.round(cmd.scaledMeterValue)) { + events += createEvent([name: "windowShade", value: state.blindsLastCommand]) + events += createEvent([name: "shadeLevel", value: state.shadeTarget, displayed: false]) + } else { + events += response([ + encap(zwave.switchMultilevelV3.switchMultilevelGet()), + "delay 500", + encap(zwave.meterV3.meterGet(scale: 0x00)) + ]) + } + } + } + events +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd, ep = null) { + log.debug "SensorMultilevelReport ${cmd}" + (ep ? " from endpoint $ep" : "") + def map = [:] + switch (cmd.sensorType) { + case 1: + map.name = "temperature" + def cmdScale = cmd.scale == 1 ? "F" : "C" + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) + map.unit = getTemperatureScale() + break + default: + map.descriptionText = cmd.toString() + } + def child = childDevices.find { it.deviceNetworkId == state.temperatureSensorDni } + if (!child) { + child = createChildDevice("qubinoTemperatureSensor", "Qubino Temperature Sensor", "Qubino Temperature Sensor", 3, "qubino", false) + state.temperatureSensorDni = child.deviceNetworkId + } + child?.sendEvent(map) + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, ep = null) { + log.warn "Unhandled ${cmd}" + (ep ? " from endpoint $ep" : "") +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private sendEventsToVenetianBlind(events) { + if (state.venetianBlindDni) { + def child = childDevices.find { it.deviceNetworkId == state.venetianBlindDni } + events.each { + child.sendEvent(it) + } + createEvent(descriptionText: "Venetian Blinds level has been updated") + } else { + log.warn "There's no venetian child device to send events to" + } +} + +private createChildDevice(componentName, componentLabel, dthName, childIt, namespace = "smartthings", isComponent = true) { + try { + def childDni = "${device.deviceNetworkId}:$childIt" + def child = addChildDevice(namespace, dthName, childDni, device.getHub().getId(), [ + completedSetup: true, + label : componentLabel, + isComponent : isComponent, + componentName : componentName, + componentLabel: componentLabel + ]) + return child + } catch(Exception e) { + log.debug "Exception: ${e}" + } +} + +private createVenetianBlindsChildDeviceIfNeeded() { + if (state.currentMode.contains("Venetian")) { + state.venetianBlindDni = createChildDevice("venetianBlind", "Venetian Blind", "Child Switch Multilevel", 2).deviceNetworkId + } +} + +private getParameterMap() {[ + [ + name: "Operating modes", key: "operatingModes", type: "enum", + parameterNumber: 71, size: 1, defaultValue: 0, + values: [ + 0: "Shutter mode", + 1: "Venetian mode (up/down and slate rotation)" + ], + description: "Set the device's operating mode." + ], + [ + name: "Slats tilting full turn time", key: "slatsTiltingFullTurnTime", type: "range", + parameterNumber: 72, size: 2, defaultValue: 150, + range: "0..32767", + description: "Specify the time required to rotate the slats 180 degrees. (100 = 1 second)" + ], + [ + name: "Slats position", key: "slatsPosition", type: "enum", + parameterNumber: 73, size: 1, defaultValue: 1, + values: [ + 0: "Slats return to previously set position only in case of Z-wave control (not valid for limit switch positions)", + 1: "Slats return to previously set position in case of Z-wave control, push-button operation or when the lower limit switch is reached" + ], + description: "This parameter defines slats position after up/down movement through Z-wave or push-buttons." + ], + [ + name: "Motor moving up/down time", key: "motorMovingUp/DownTime", type: "range", + parameterNumber: 74, size: 2, defaultValue: 0, + range: "0..32767", + description: "Set the amount of time it takes to completely open or close shutter. Check manual for more detailed guidance." + ], + [ + name: "Motor operation detection", key: "motorOperationDetection", type: "range", + parameterNumber: 76, size: 1, defaultValue: 30, + range: "0..127", + description: "Power usage threshold which will be interpreted as motor reaching the limit switch." + ], + [ + name: "Forced Shutter calibration", key: "forcedShutterCalibration", type: "enum", + parameterNumber: 78, size: 1, defaultValue: 0, + values: [ + 0: "0: Calibration finished or not started", + 1: "1: Start calibration process" + ], + description: "By modifying the parameters setting from 0 to 1 a Shutter enters the calibration mode. When calibration process is finished, completing full cycle - up, down and up, set this parameter value back to 0." + ] +]} \ No newline at end of file diff --git a/devicetypes/qubino/qubino-temperature-sensor.src/qubino-temperature-sensor.groovy b/devicetypes/qubino/qubino-temperature-sensor.src/qubino-temperature-sensor.groovy new file mode 100644 index 00000000000..5fad9d7d548 --- /dev/null +++ b/devicetypes/qubino/qubino-temperature-sensor.src/qubino-temperature-sensor.groovy @@ -0,0 +1,52 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Qubino Temperature Sensor", namespace: "qubino", author: "SmartThings", mnmn: "SmartThings", vid: "SmartThings-smartthings-Qubino_Temperature_Sensor", ocfDeviceType: "oic.d.thermostat") { + capability "Health Check" + capability "Refresh" + capability "Sensor" + capability "Temperature Measurement" + } + + tiles(scale: 2) { + multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState("temperature", label:'${currentValue}°') + } + } + + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" + } + main "temperature" + details(["temperature", "refresh"]) + } +} + +def installed() { + log.debug "Child Temperature Sensor installed" +} + +def updated() { + log.debug "Child Temperature Sensor updated" +} + +def ping() { + refresh() +} + +def refresh() { + parent.refreshChild() +} \ No newline at end of file diff --git a/devicetypes/rachio/rachio-iro2-zone.src/rachio-iro2-zone.groovy b/devicetypes/rachio/rachio-iro2-zone.src/rachio-iro2-zone.groovy index 1d15af72f77..3464acb15e0 100644 --- a/devicetypes/rachio/rachio-iro2-zone.src/rachio-iro2-zone.groovy +++ b/devicetypes/rachio/rachio-iro2-zone.src/rachio-iro2-zone.groovy @@ -14,11 +14,6 @@ * for the specific language governing permissions and limitations under the License. * */ - -import java.text.SimpleDateFormat - -def devVer() { return "2.0.0" } - metadata { definition (name: "Rachio Zone", namespace: "rachio", author: "Rachio") { capability "Refresh" @@ -27,56 +22,6 @@ metadata { capability "Valve" capability "Sensor" capability "Health Check" - - attribute "zoneNumber", "number" - attribute "zoneName", "string" - attribute "watering", "string" - - attribute "zoneSquareFeet", "number" - attribute "zoneWaterTime", "number" - attribute "zoneTotalDuration", "number" - attribute "rootZoneDepth", "number" - attribute "availableWater", "string" - - attribute "efficiency", "string" - attribute "maxRuntime", "number" - attribute "saturatedDepthOfWater", "string" - attribute "depthOfWater", "string" - - //current_schedule data - attribute "scheduleType", "string" - - attribute "zoneDuration", "number" - attribute "zoneElapsed", "number" - attribute "zoneStartDate", "string" - attribute "zoneCycleCount", "number" - - //custom nozzle data - attribute "nozzleName", "string" - - //custom soil data - attribute "soilName", "string" - - //custom slope data - attribute "slopeName", "string" - - //custom crop data - attribute "cropName", "string" - - //custom shade data - attribute "shadeName", "string" - attribute "inStandby", "string" - attribute "lastUpdatedDt", "string" - - command "stopWatering" - command "decZoneWaterTime" - command "incZoneWaterTime" - command "setZoneWaterTime", ["number"] - command "startZone" - - command "open" - command "close" - command "pause" } simulator { @@ -85,85 +30,14 @@ metadata { tiles (scale: 2){ multiAttributeTile(name: "valveTile", type: "generic", width: 6, height: 4) { - tileAttribute("device.watering", key: "PRIMARY_CONTROL" ) { - attributeState "off", label: 'Off', action: "open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"updating" - attributeState "offline", label: 'Offline', icon: "st.valves.water.closed", backgroundColor: "#cccccc" - attributeState "disabled", label: 'Disabled', icon: "st.valves.water.closed", backgroundColor: "#cccccc" - attributeState "standby", label: 'Standby Mode', icon: "st.valves.water.closed", backgroundColor: "#cccccc" - attributeState "on", label: 'Watering', action: "close", icon: "st.valves.water.open", backgroundColor: "#00a0dc", nextState: "updating" - attributeState "updating", label:"Working" - } - tileAttribute("device.zoneRunStatus", key: "SECONDARY_CONTROL") { - attributeState("default", label:'${currentValue}') + tileAttribute("device.switch", key: "PRIMARY_CONTROL" ) { + attributeState "off", label: 'Off', action: "open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"on" + attributeState "on", label: 'Watering', action: "close", icon: "st.valves.water.open", backgroundColor: "#00a0dc", nextState: "off" } } - valueTile("zoneName", "device.zoneName", inactiveLabel: true, width: 3, height: 1, decoration: "flat", wordWrap: true) { - state("default", label: 'Zone:\n${currentValue}') - } - - valueTile("blank11", "device.blank", width: 1, height: 1, decoration: "flat") { - state("default", label: '') - } - - //zone Water time control - valueTile("scheduleType", "device.scheduleType", width: 2, height: 1, decoration: "flat", wordWrap: true) { - state("default", label: 'Schedule Type:\n${currentValue}') - } - valueTile("efficiency", "device.efficiency", width: 2, height: 1, decoration: "flat", wordWrap: true) { - state("default", label: 'Efficiency:\n${currentValue}') - } - valueTile("zoneSquareFeet", "device.zoneSquareFeet", inactiveLabel: false, width: 2 , height: 1, decoration: "flat") { - state "default", label: 'Zone Area\n${currentValue} sq ft' - } - standardTile("leftZoneTimeButton", "device.zoneWaterTime", inactiveLabel: false, decoration: "flat") { - state "default", action:"decZoneWaterTime", icon:"st.thermostat.thermostat-left" - } - valueTile("zoneWaterTime", "device.zoneWaterTime", width: 2, height: 1, decoration: "flat") { - state "default", label:'Manual Zone Time:\n${currentValue} Minutes' - } - controlTile("zoneWaterTimeSliderTile", "device.zoneWaterTime", "slider", width: 4, height: 1, range:'(0..60)') { - state "default", label: 'Manual Zone Time', action:"setZoneWaterTime" - } - standardTile("rightZoneTimeButton", "device.zoneWaterTime", inactiveLabel: false, decoration: "flat") { - state "default", action:"incZoneWaterTime", icon:"st.thermostat.thermostat-right" - } - valueTile("zoneWaterTimeVal", "device.zoneWaterTime", inactiveLabel: false, width: 2 , height: 1, decoration: "flat") { - state "default", label: 'Water Time\n${currentValue} Minutes' - } - valueTile("startZoneTile", "device.zoneWaterTime", inactiveLabel: false, width: 2 , height: 1, decoration: "flat") { - state "default", label: 'Run This Zone\n${currentValue} Minutes', action:'startZone' - } - - //nozzle Tiles - valueTile("nozzleName", "device.nozzleName", inactiveLabel: true, width: 2, height: 1, decoration: "flat") { - state "default", label: 'Nozzle:\n${currentValue}' - } - //Soil Tiles - valueTile("soilName", "device.soilName", inactiveLabel: true, width: 2, height: 1, decoration: "flat") { - state "default", label: 'Soil:\n${currentValue}' - } - //Slope Tiles - valueTile("slopeName", "device.slopeName", inactiveLabel: true, width: 2, height: 1, decoration: "flat") { - state "default", label: 'Slope:\n${currentValue}' - } - //Crop Tiles - valueTile("cropName", "device.cropName", inactiveLabel: true, width: 2, height: 1, decoration: "flat") { - state "default", label: 'Crop:\n${currentValue}' - } - //Shade Tiles - valueTile("shadeName", "device.shadeName", inactiveLabel: true, width: 2, height: 1, decoration: "flat") { - state "default", label: 'Shade:\n${currentValue}' - } - - standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { - state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" - } - standardTile("zoneImage", "device.zoneImage", inactiveLabel: false, width: 1, height: 1, decoration: "flat") { - state "default", label: '', icon: "http://media.rach.io/images/zone/default/default_zone.jpg" - } } main "valveTile" - details(["valveTile", "zoneImage", "zoneName", "scheduleType", "nozzleName", "soilName", "slopeName", "cropName", "shadeName", "zoneSquareFeet", "leftZoneTimeButton", "zoneWaterTime", "rightZoneTimeButton", "startZoneTile", "lastUpdatedDt", "refresh"]) + details(["valveTile"]) } // parse events into attributes @@ -173,16 +47,6 @@ def parse(String description) { def initialize() { sendEvent(name: "DeviceWatch-Enroll", value: groovy.json.JsonOutput.toJson(["protocol":"cloud", "scheme":"untracked"]), displayed: false) - - verifyDataAttr() -} - -def verifyDataAttr() { - updateDataValue("HealthEnrolled", "true") - updateDataValue("manufacturer", "Rachio") -// getDevGeneration is not defined in the connect app... -// def gen = state.deviceId ? parent?.getDevGeneration(state.deviceId) : null -// updateDataValue("model", "${device?.name}${gen ? " ($gen)" : ""}") } void installed() { @@ -202,302 +66,24 @@ def ping() { } def generateEvent(Map results) { - if (!state.swVersion || state.swVersion != devVer()) { - initialize() - state.swVersion = devVer() - } if (results) { if (!results.data?.enabled) { - sendEvent(name: 'zoneRunStatus', value: "Disabled", displayed: true) - sendEvent(name: 'watering', value: "disabled", displayed: false) sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) return } // log.debug results - state.pauseInStandby = (results.pauseInStandby == true) - state.zoneId = results.data?.id - state.deviceId = results.devId ? results.devId.toString() : null - state.zoneNum = results.data?.zoneNumber - zoneNameEvent(results.data?.name) - zoneNumEvent(results.data?.zoneNumber) - state.zoneImageUrl = results.data?.imageUrl - if (results.status == "ONLINE") { - state.inStandby = results.standby - sendEvent(name: 'inStandby', value: results.standby, displayed: true) sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) - if (results.standby == true && results.pauseInStandby == true) { - markStandby() - } else { - isWateringEvent(results.schedData?.status, results.schedData?.zoneId) - } - lastUpdatedEvent() } else { markOffLine() } - if(!device.currentValue("zoneWaterTime")) { - setZoneWaterTime(parent?.settings?.defaultZoneTime.toInteger()) - } - - availableWaterEvent(results.data?.availableWater) - rootZoneDepthEvent(results.data?.rootZoneDepth) - zoneSquareFeetEvent(results.data?.yardAreaSquareFeet) - zoneTotalDurationEvent(results.data?.runtime) - saturatedDepthOfWaterEvent(results.data?.saturatedDepthOfWater) - depthOfWaterEvent(results.data?.depthOfWater) - maxRuntimeEvent(results.data?.maxRuntime) - efficiencyEvent(results.data?.efficiency) - scheduleDataEvent(results.schedData) - customNozzleDataEvent(results.data?.customNozzle) - customSoilDataEvent(results.data?.customSoil) - customSlopeDataEvent(results.data?.customSlope) - customCropDataEvent(results.data?.customCrop) - customShadeDataEvent(results.data?.customShade) - } -} - -def getDurationDesc(long secondsCnt) { - int seconds = secondsCnt %60 - secondsCnt -= seconds - long minutesCnt = secondsCnt / 60 - long minutes = minutesCnt % 60 - minutesCnt -= minutes - long hoursCnt = minutesCnt / 60 - return "${minutes} min ${(seconds >= 0 && seconds < 10) ? "0${seconds}" : "${seconds}"} sec" -} - -def getDurationMinDesc(long secondsCnt) { - int seconds = secondsCnt %60 - secondsCnt -= seconds - long minutesCnt = secondsCnt / 60 - long minutes = minutesCnt % 60 - minutesCnt -= minutes - long hoursCnt = minutesCnt / 60 - return "${minutes}" -} - -def lastUpdatedEvent() { - state.lastUpdatedDt = formatDt(new Date())?.toString() - sendEvent(name: 'lastUpdatedDt', value: state.lastUpdatedDt, displayed: false) -} - -def markOffLine() { - log.trace "Watering (Offline)" - sendEvent(name: 'watering', value: "offline", displayed: true) - sendEvent(name: 'valve', value: "closed", displayed: false) - sendEvent(name: 'switch', value: "off", displayed: false) - sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - sendEvent(name: 'zoneRunStatus', value: "Device is Offline", displayed: false) -} - -def markStandby() { - log.trace "Watering (Standby Mode)" - sendEvent(name: 'watering', value: "standby", displayed: true) - sendEvent(name: 'valve', value: "closed", displayed: false) - sendEvent(name: 'switch', value: "off", displayed: false) - sendEvent(name: 'zoneRunStatus', value: "Device in Standby Mode", displayed: false) -} - -def isWateringEvent(status, zoneId) { - //log.trace "isWateringEvent..." - def isOn = (status == "PROCESSING" && device.deviceNetworkId == zoneId) - def newState = isOn ? "on" : "off" - log.debug "Watering ${newState}" - sendEvent(name: 'watering', value: newState, displayed: true) - sendEvent(name: 'switch', value: newState, displayed: false) - sendEvent(name: 'valve', value: (isOn ? "open" : "closed"), displayed: false) -} - -def zoneTotalDurationEvent(val) { - def newState = val ? val.toInteger() : 0 - log.debug "Zone Total Duration Value ${newState}" - sendEvent(name:'zoneTotalDuration', value: newState, displayed: true) -} - -def saturatedDepthOfWaterEvent(val) { - def newState = val ? val.toDouble() : 0.0 - log.debug "Saturated Depth Of Water Value ${newState}" - sendEvent(name:'saturatedDepthOfWater', value: newState, displayed: true) -} - -def depthOfWaterEvent(val) { - def newState = val ? val.toDouble() : 0.0 - log.debug "Depth Of Water Value ${newState}" - sendEvent(name:'depthOfWater', value: newState, displayed: true) -} - -def efficiencyEvent(val) { - def newState = val ? val.toDouble() : 0.0 - log.debug "Efficiency Value ${newState}" - sendEvent(name:'efficiency', value: newState, displayed: false) -} - -def maxRuntimeEvent(val) { - def newState = val ? val.toInteger() : 0 - log.debug "Max Runtime Value ${newState}" - sendEvent(name:'maxRuntime', value: newState, displayed: false) -} - -def availableWaterEvent(val) { - def newState = val ? val.toDouble() : 0.0 - log.debug "Available Water Value ${newState}" - sendEvent(name:'availableWater', value: newState, displayed: true) -} - -def zoneSquareFeetEvent(val) { - def newState = val ? val.toInteger() : 0 - log.debug "Zone Area Square Feet ${newState}" - sendEvent(name:'zoneSquareFeet', value: newState, displayed: true) -} - -def rootZoneDepthEvent(val) { - def newState = val ? val.toInteger() : 0 - log.debug "Root Zone Depth Value ${newState}" - sendEvent(name:'rootZoneDepth', value: newState, displayed: false) -} - -def zoneNumEvent(val) { - def newState = val ? val.toInteger() : 0 - log.debug "Zone Number ${newState}" - sendEvent(name:'zoneNumber', value: newState, displayed: true) -} - -def zoneNameEvent(val) { - def newState = val ? val.toString() : "unknown" - log.debug "Zone Name ${newState}" - sendEvent(name:'zoneName', value: newState, displayed: true) -} - -def setZoneWaterTime(timeVal) { - def newVal = timeVal ? timeVal.toInteger() : parent?.settings?.defaultZoneTime.toInteger() - log.debug "Manual Zone Water Time ${newVal}" - sendEvent(name: 'zoneWaterTime', value: newVal, displayed: true) -} - -def fmtString(str) { - if (str) { - def out = [] - def tmp = str?.replaceAll("_", " ")?.toLowerCase()?.split(" ") - tmp?.each { out.push(it?.toString().capitalize()) } - return out.join(" ") - } - return null -} -def scheduleDataEvent(data) { - //log.trace "scheduleDataEvent($data)..." - state.curSchedData = data - def curSchedType = !data?.type ? "off" : data?.type?.toString().toLowerCase() - state.curSchedType = curSchedType - state.curScheduleId = !data?.scheduleId ? null : data?.scheduleId - state.curScheduleRuleId = !data?.scheduleRuleId ? null : data?.scheduleRuleId - - def zoneId = !data?.zoneId ? null : data?.zoneId - def zoneStartDate = (zoneId == device.deviceNetworkId && data?.zoneStartDate) ? data?.zoneStartDate : null - def zoneDuration = (zoneId == device.deviceNetworkId && data?.zoneDuration) ? data?.zoneDuration : null - def timeDiff = data?.zoneStartDate ? GetTimeValDiff(data?.zoneStartDate.toLong()) : 0 - def elapsedDuration = data?.zoneStartDate ? getDurationMinDesc(Math.round(timeDiff)) : 0 - def wateringDuration = zoneDuration ? getDurationMinDesc(zoneDuration) : 0 - def zoneRunStatus = ((!zoneStartDate && !zoneDuration) || (zoneId != device.deviceNetworkId)) ? - "Status: Idle" : "${curSchedType == "automatic" ? "Scheduled" : "Manual"} Watering: ${elapsedDuration} of ${wateringDuration} Minutes" - def zoneCycleCount = (zoneId != device.deviceNetworkId && !data?.totalCycleCount) ? 0 : data?.totalCycleCount - - sendEvent(name: 'scheduleType', value: curSchedType?.capitalize(), displayed: true) - sendEvent(name: 'zoneDuration', value: zoneDuration, displayed: true) - - sendEvent(name: 'zoneElapsed', value: (zoneDuration && timeDiff && timeDiff > 0 ? timeDiff : null), displayed: false) - if(!state.inStandby && (device.currentValue("watering") != "offline")) { - log.debug "ZoneRunStatus ${zoneRunStatus}" - sendEvent(name: 'zoneRunStatus', value: zoneRunStatus, displayed: true) - } - sendEvent(name: 'zoneCycleCount', value: zoneCycleCount, displayed: true) - sendEvent(name: 'isCycling', value: ((zoneId == device.deviceNetworkId && data?.cycling) ? "True" : "False"), displayed: true) - sendEvent(name: 'zoneStartDate', value: (zoneStartDate ? epochToDt(zoneStartDate).toString() : "Not Active"), displayed: true) -} - -def customNozzleDataEvent(data) { - //log.trace "customNozzleDataEvent($data)" - if(data?.name) { - sendEvent(name:'nozzleName', value: fmtString(data.name).toString(), displayed: true) - } -} - -def customSoilDataEvent(data) { - //log.trace "customSoilDataEvent($data)" - if (data?.name) { - sendEvent(name:'soilName', value: fmtString(data.name).toString(), displayed: true) - } -} - -def customSlopeDataEvent(data) { - //log.trace "customSlopeDataEvent($data)" - sendEvent(name:'slopeName', value: (data?.name ? fmtString(data.name).toString() : "N/A"), displayed: true) -} - -def customCropDataEvent(data) { - //log.trace "customCropDataEvent($data)" - if (data?.name) { - sendEvent(name:'cropName', value: fmtString(data?.name).toString(), displayed: true) - } -} - -def customShadeDataEvent(data) { - //log.trace "customShadeDataEvent($data)" - if (data?.name) { - sendEvent(name:'shadeName', value: fmtString(data?.name).toString(), displayed: true) } } def refresh() { - //log.trace "refresh..." parent?.poll(this) } -def incZoneWaterTime() { - // log.debug "Decrease Zone Runtime" - if (device.currentValue("DeviceWatch-DeviceStatus") == "online") { - def value = device.latestValue('zoneWaterTime') - setZoneWaterTime(value + 1) - } -} - -def decZoneWaterTime() { - // log.debug "Increase Zone Runtime" - if (device.currentValue("DeviceWatch-DeviceStatus") == "online") { - def value = device.latestValue('zoneWaterTime') - setZoneWaterTime(value - 1) - } -} - -def isCmdOk2Run() { - //log.trace "isCmdOk2Run..." - if (device.currentValue("DeviceWatch-DeviceStatus") == "offline") { - log.warn "Skipping the request... Because the zone is unable to send commands while it's in an Offline State." - return false - } - if(state.pauseInStandby && state.inStandby) { - log.warn "Skipping the request... Because the zone is unable to send commands while the controller is in standby mode." - return false - } - return true -} - -def startZone() { - log.trace "startZone()..." - if (isCmdOk2Run()) { - def zoneNum = device.latestValue('zoneNumber') - def waterTime = device.latestValue('zoneWaterTime') - log.debug("Starting Watering for Zone (${zoneNum}) for (${waterTime}) Minutes") - if (parent?.startZone(this, state.deviceId, zoneNum, waterTime)) { - log.debug "runThisZone was Sent Successfully" - sendEvent(name:'watering', value: "on", displayed: true) - sendEvent(name:'switch', value: "on", displayed: false) - sendEvent(name:'valve', value: "open", displayed: false) - } else { - markOffLine() - } - } -} - def on() { log.trace "zone on..." if (isCmdOk2Run()) { @@ -534,7 +120,6 @@ def close() { if (device.currentValue("valve") == "open") { if (parent?.off(this, state.deviceId)) { log.info "Zone was Stopped Successfully..." - sendEvent(name:'watering', value: "off", displayed: true) sendEvent(name:'switch', value: "off", displayed: false) sendEvent(name:'valve', value: "closed", displayed: false) } @@ -543,56 +128,40 @@ def close() { } } -// To be used directly by smart apps -def stopWatering() { - log.trace "stopWatering" - close() -} - -def getDtNow() { - def now = new Date() - return formatDt(now, false) -} - -def epochToDt(val) { - if (val) { - return formatDt(new Date(val)) - } +def markOffLine() { + log.trace "Watering (Offline)" + sendEvent(name: 'valve', value: "closed", displayed: false) + sendEvent(name: 'switch', value: "off", displayed: false) + sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) } -def formatDt(dt, mdy = true) { - def formatVal = mdy ? "MMM d, yyyy - h:mm:ss a" : "E MMM dd HH:mm:ss z yyyy" - def tf = new SimpleDateFormat(formatVal) - if (location?.timeZone) { - tf.setTimeZone(location?.timeZone) +def startZone() { + log.trace "startZone()..." + if (isCmdOk2Run()) { + def zoneNum = device.latestValue('zoneNumber') + def waterTime = 10; + log.debug("Starting Watering for Zone (${zoneNum}) for (${waterTime}) Minutes") + if (parent?.startZone(this, state.deviceId, zoneNum, waterTime)) { + log.debug "runThisZone was Sent Successfully" + sendEvent(name:'switch', value: "on", displayed: false) + sendEvent(name:'valve', value: "open", displayed: false) + } else { + markOffLine() + } } - return tf.format(dt) } -//Returns time differences is seconds -def GetTimeValDiff(timeVal) { - try { - def start = new Date(timeVal).getTime() - def now = new Date().getTime() - def diff = (int) (long) (now - start) / 1000 - //log.debug "diff: $diff" - return diff - } - catch (ex) { - log.error "GetTimeValDiff Exception: ${ex}" - return 1000 - } +// To be used directly by smart apps +def stopWatering() { + log.trace "stopWatering" + close() } -def getTimeDiffSeconds(strtDate, stpDate=null) { - if((strtDate && !stpDate) || (strtDate && stpDate)) { - def now = new Date() - def stopVal = stpDate ? stpDate.toString() : formatDt(now, false) - def start = Date.parse("E MMM dd HH:mm:ss z yyyy", strtDate).getTime() - def stop = Date.parse("E MMM dd HH:mm:ss z yyyy", stopVal).getTime() - def diff = (int) (long) (stop - start) / 1000 - return diff - } else { - return null +def isCmdOk2Run() { + //log.trace "isCmdOk2Run..." + if (device.currentValue("DeviceWatch-DeviceStatus") == "offline") { + log.warn "Skipping the request... Because the zone is unable to send commands while it's in an Offline State." + return false } + return true } diff --git a/devicetypes/rooms-beautiful/rooms-beautiful-curtain.src/rooms-beautiful-curtain.groovy b/devicetypes/rooms-beautiful/rooms-beautiful-curtain.src/rooms-beautiful-curtain.groovy new file mode 100644 index 00000000000..b39710f8f19 --- /dev/null +++ b/devicetypes/rooms-beautiful/rooms-beautiful-curtain.src/rooms-beautiful-curtain.groovy @@ -0,0 +1,295 @@ +/** + * + * Copyright 2019 SmartThings + * + * 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. + */ + +import groovy.json.JsonOutput +import physicalgraph.zigbee.zcl.DataType + +metadata { + definition(name: "Rooms Beautiful Curtain", namespace: "Rooms Beautiful", author: "Alex Feng", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-shade-2") { + capability "Actuator" + capability "Battery" + capability "Configuration" + capability "Refresh" + capability "Health Check" + capability "Window Shade" + capability "Switch" + capability "Switch Level" + + attribute("replay", "enum") + attribute("battLife", "enum") + + command "cont" + + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0006, FC00, DC00, 0102", deviceJoinName: "Rooms Beautiful Window Treatment", manufacturer: "Rooms Beautiful", model: "C001" //Curtain + } + + preferences { + input name: "invert", type: "bool", title: "Invert Direction", description: "Invert Curtain Direction", defaultValue: false, displayDuringSetup: false, required: true + } + + tiles(scale: 2) { + multiAttributeTile(name: "windowShade", type: "generic", width: 6, height: 4) { + tileAttribute("device.windowShade", key: "PRIMARY_CONTROL") { + attributeState "open", label: 'Open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing" + attributeState "closed", label: 'Closed', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening" + attributeState "partially open", label: 'Partially open', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#d45614", nextState: "closing" + attributeState "opening", label: 'Opening', action: "close", icon: "http://www.ezex.co.kr/img/st/window_open.png", backgroundColor: "#00A0DC", nextState: "closing" + attributeState "closing", label: 'Closing', action: "open", icon: "http://www.ezex.co.kr/img/st/window_close.png", backgroundColor: "#ffffff", nextState: "opening" + } + tileAttribute("device.battLife", key: "SECONDARY_CONTROL") { + attributeState "full", icon: "https://raw.githubusercontent.com/gearsmotion789/ST-Images/master/full.png", label: "" + attributeState "medium", icon: "https://raw.githubusercontent.com/gearsmotion789/ST-Images/master/medium.png", label: "" + attributeState "low", icon: "https://raw.githubusercontent.com/gearsmotion789/ST-Images/master/low.png", label: "" + attributeState "dead", icon: "https://raw.githubusercontent.com/gearsmotion789/ST-Images/master/dead.png", label: "" + } + tileAttribute("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action: "switch level.setLevel" + } + } + standardTile("contPause", "device.replay", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "pause", label: "Pause", icon: 'https://raw.githubusercontent.com/gearsmotion789/ST-Images/master/pause.png', action: 'pause', backgroundColor: "#e86d13", nextState: "cont" + state "cont", label: "Cont.", icon: 'https://raw.githubusercontent.com/gearsmotion789/ST-Images/master/play.png', action: 'cont', backgroundColor: "#90d2a7", nextState: "pause" + } + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { + state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh" + } + + main "windowShade" + details(["windowShade", "contPause", "refresh"]) + } +} + +private getCLUSTER_WINDOW_COVERING() { + 0x0102 +} +private getCOMMAND_GOTO_LIFT_PERCENTAGE() { + 0x05 +} +private getATTRIBUTE_POSITION_LIFT() { + 0x0008 +} +private getBATTERY_VOLTAGE() { + 0x0020 +} + +// Parse incoming device messages to generate events +def parse(String description) { + // FYI = event.name refers to attribute name & not the tile's name + + def linkText = getLinkText(device) + def event = zigbee.getEvent(description) + def descMap = zigbee.parseDescriptionAsMap(description) + def value + def attrId + + if (event) { + if (!descMap.attrId) + sendEvent(name: "replay", value: "pause") + + if (event.name == "switch" || event.name == "windowShade") { + if (event.value == "on" || event.value == "open") { + log.info "${linkText} - Open" + sendEvent(name: "switch", value: "on") + sendEvent(name: "windowShade", value: "open") + } else { + log.info "${linkText} - Close" + sendEvent(name: "switch", value: "off") + sendEvent(name: "windowShade", value: "closed") + } + } + } else { + if (descMap.attrId) { + if (descMap.clusterInt != 0xDC00) { + value = Integer.parseInt(descMap.value, 16) + attrId = Integer.parseInt(descMap.attrId, 16) + } + } + + switch (descMap.clusterInt) { + case zigbee.POWER_CONFIGURATION_CLUSTER: + if (attrId == BATTERY_VOLTAGE) + handleBatteryEvent(value) + break; + case CLUSTER_WINDOW_COVERING: + if (attrId == ATTRIBUTE_POSITION_LIFT) { + log.info "${linkText} - Level: ${value}" + sendEvent(name: "level", value: value) + + if (value == 0 || value == 100) { + sendEvent(name: "switch", value: value == 0 ? "off" : "on") + sendEvent(name: "windowShade", value: value == 0 ? "closed" : "open") + } else if (value > 0 && value < 100) { + sendEvent(name: "replay", value: "cont") + sendEvent(name: "windowShade", value: "partially open") + } + } + break; + case 0xFC00: + if (description?.startsWith('read attr -')) + log.info "${linkText} - Inverted: ${value}" + else + log.debug "${linkText} - Inverted set to: ${invert}" + break; + case 0xDC00: + value = descMap.value + def shortAddr = value.substring(4) + def lqi = zigbee.convertHexToInt(value.substring(2, 4)) + def rssi = (byte) zigbee.convertHexToInt(value.substring(0, 2)) + log.info "${linkText} - Parent Addr: ${shortAddr} **** LQI: ${lqi} **** RSSI: ${rssi}" + break; + default: + log.warn "${linkText} - DID NOT PARSE MESSAGE for description: $description" + log.debug descMap + break; + } + } +} + +def off() { + zigbee.off() + + sendEvent(name: "level", value: 0) +} + +def on() { + zigbee.on() + + sendEvent(name: "level", value: 100) +} + +def close() { + zigbee.off() + + sendEvent(name: "level", value: 0) +} + +def open() { + zigbee.on() + + sendEvent(name: "level", value: 100) +} + +def pause() { + zigbee.command(CLUSTER_WINDOW_COVERING, 0x02) + + sendEvent(name: "replay", value: "cont") + + sendEvent(name: "windowShade", value: "partially open") +} + +def cont() { + zigbee.command(CLUSTER_WINDOW_COVERING, 0x02) + + sendEvent(name: "replay", value: "pause") +} + +def setLevel(value) { + def time + if (state.updatedDate == null) { + time = now() + } else { + time = now() - state.updatedDate + } + state.updatedDate = now() + log.trace("Time: ${time}") + + if (time > 1000) { + log.debug("Setting level to: ${value}") + zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_GOTO_LIFT_PERCENTAGE, zigbee.convertToHexString(100 - value, 2)) + + sendEvent(name: "level", value: value) + } +} + +private handleBatteryEvent(volts) { + def linkText = getLinkText(device) + + if (volts > 30 || volts < 20) { + log.warn "${linkText} - Ignoring invalid value for voltage (${volts/10}V)" + } else { + def batteryMap = [30: "full", 29: "full", 28: "full", 27: "medium", 26: "low", 25: "dead"] + + def value = batteryMap[volts] + if (value != null) { + def minVolts = 25 + def maxVolts = 30 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + def percent = Math.min(100, roundedPct) + + log.info "${linkText} - Batt: ${value} **** Volts: ${volts/10}v **** Percent: ${percent}%" + sendEvent(name: "battery", value: percent) + sendEvent(name: "battLife", value: value) + } + } +} + +def refresh() { + zigbee.onOffRefresh() + + zigbee.readAttribute(CLUSTER_WINDOW_COVERING, ATTRIBUTE_POSITION_LIFT) + // Window Lift Percentage Attribute + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_VOLTAGE) + // Battery Voltage Attribute + + // For Diagnostics + zigbee.readAttribute(0xFC00, 0x0000) + // Invert CLuster + zigbee.readAttribute(0xDC00, 0x0000) // Parent, LQI, RSSI Cluster +} + +def ping() { + return refresh() +} + +def configure() { + // Device-Watch allows 2 check-in misses from device + ping (plus 2 min lag time) + sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + log.debug "Configuring Reporting and Bindings." + return refresh() +} + +def installed() { + sendEvent(name: "supportedWindowShadeCommands", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false) + sendEvent(name: "battery", value: 100) + sendEvent(name: "battLife", value: "full") + response(refresh()) +} + +def updated() { + if (invert.value == false) + response(normal()) + else if (invert.value == true) + response(reverse()) +} + +def normal() { + if (device.currentState("windowShade").value == "open") { + sendEvent(name: "switch", value: "off") + sendEvent(name: "windowShade", value: "closed") + sendEvent(name: "level", value: 100 - Integer.parseInt(device.currentState("level").value)) + log.debug("normal-close") + zigbee.writeAttribute(0xFC00, 0x0000, DataType.BOOLEAN, 0x00) + } else { + sendEvent(name: "switch", value: "on") + sendEvent(name: "windowShade", value: "open") + sendEvent(name: "level", value: 100 - Integer.parseInt(device.currentState("level").value)) + log.debug("normal-open") + zigbee.writeAttribute(0xFC00, 0x0000, DataType.BOOLEAN, 0x00) + } +} + +def reverse() { + if (device.currentState("windowShade").value == "open") { + sendEvent(name: "switch", value: "off") + sendEvent(name: "windowShade", value: "closed") + sendEvent(name: "level", value: 100 - Integer.parseInt(device.currentState("level").value)) + log.debug("reverse-close") + zigbee.writeAttribute(0xFC00, 0x0000, DataType.BOOLEAN, 0x01) + } else { + sendEvent(name: "switch", value: "on") + sendEvent(name: "windowShade", value: "open") + sendEvent(name: "level", value: 100 - Integer.parseInt(device.currentState("level").value)) + log.debug("reverse-open") + zigbee.writeAttribute(0xFC00, 0x0000, DataType.BOOLEAN, 0x01) + } +} diff --git a/devicetypes/samsungsds/samsung-smart-doorlock.src/i18n/messages.properties b/devicetypes/samsungsds/samsung-smart-doorlock.src/i18n/messages.properties index 44d5ff15148..da5f9cfe943 100755 --- a/devicetypes/samsungsds/samsung-smart-doorlock.src/i18n/messages.properties +++ b/devicetypes/samsungsds/samsung-smart-doorlock.src/i18n/messages.properties @@ -13,8 +13,10 @@ # under the License. # Chinese +'''Samsung Door Lock'''.zh-cn=SDS联网型智能锁 '''Samsung Smart Doorlock'''.zh-cn=SDS联网型智能锁 # Korean (ko) +'''Samsung Door Lock'''.ko=삼성 스마트 도어락 '''Samsung Smart Doorlock'''.ko=삼성 스마트 도어락 diff --git a/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy b/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy index a80df0e530e..3ee4c5f3868 100755 --- a/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy +++ b/devicetypes/samsungsds/samsung-smart-doorlock.src/samsung-smart-doorlock.groovy @@ -27,7 +27,7 @@ metadata { capability "Health Check" capability "Refresh" - fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0004, 0005, 0009, 0101", outClusters: "0019", manufacturer: "SAMSUNG SDS" + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0004, 0005, 0009, 0101", outClusters: "0019", manufacturer: "SAMSUNG SDS", deviceJoinName: "Samsung Door Lock" } diff --git a/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy b/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy index 9d72c392e7e..028431906cb 100644 --- a/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy +++ b/devicetypes/sinope-technologies/dm2500zb-sinope-dimmer.src/dm2500zb-sinope-dimmer.groovy @@ -1,7 +1,6 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1.3.0 SVN-571 * 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. @@ -14,8 +13,8 @@ preferences { input("LedIntensityParam", "number", title:"Indicator light intensity (1..100) (default: blank)", range:"1..100", description:"optional") input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") } metadata { @@ -30,7 +29,7 @@ metadata { attribute "swBuild","string"// earliers versions of the DM2500ZB does not support the minimal intensity. theses dimmers can be identified by their swBuild under the value 106 - fingerprint manufacturer: "Sinope Technologies", model: "DM2500ZB", deviceJoinName: "DM2500ZB" + fingerprint manufacturer: "Sinope Technologies", model: "DM2500ZB", deviceJoinName: "Sinope Dimmer Switch" //DM2500ZB } tiles(scale: 2) @@ -71,7 +70,7 @@ def parse(String description) else { traceEvent(settings.logFilter, "send event : $event", settings.trace, get_LOG_DEBUG()) sendEvent(event) - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } } else @@ -313,35 +312,25 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } } \ No newline at end of file diff --git a/devicetypes/sinope-technologies/rm3250zb-sinope-load-controller.src/rm3250zb-sinope-load-controller.groovy b/devicetypes/sinope-technologies/rm3250zb-sinope-load-controller.src/rm3250zb-sinope-load-controller.groovy index b3a315490b4..0d424491685 100644 --- a/devicetypes/sinope-technologies/rm3250zb-sinope-load-controller.src/rm3250zb-sinope-load-controller.groovy +++ b/devicetypes/sinope-technologies/rm3250zb-sinope-load-controller.src/rm3250zb-sinope-load-controller.groovy @@ -1,7 +1,6 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1.3.0 SVN-571 * 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. @@ -11,11 +10,11 @@ metadata { preferences { input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") } - definition (name: "RM3250ZB Sinope Load Controller", namespace: "Sinope Technologies", author: "Sinope Technologies", , ocfDeviceType: "oic.d.switch") { + definition (name: "RM3250ZB Sinope Load Controller", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.switch", mnmn: "SmartThings", vid: "SmartThings-smartthings-ZigBee_Switch_Power") { capability "Refresh" capability "Switch" @@ -24,7 +23,7 @@ metadata { capability "Power Meter" capability "Health Check" - fingerprint manufacturer: "Sinope Technologies", model: "RM3250ZB", deviceJoinName: "RM3250ZB" + fingerprint manufacturer: "Sinope Technologies", model: "RM3250ZB", deviceJoinName: "Sinope Switch" //RM3250ZB } tiles(scale: 2) { @@ -92,18 +91,17 @@ def refresh() { traceEvent(settings.logFilter, "Refresh.", settings.trace, get_LOG_DEBUG()) return zigbee.readAttribute(0x0006, 0x0000) + //read on/off zigbee.readAttribute(0x0B04, 0x050B) + //read active power - zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) + //configure reporting of on/off - zigbee.configureReporting(0x0B04, 0x050B, 0x29, 30, 599, 0x64) // configure reporting of active power + configure() } def configure() { traceEvent(settings.logFilter, "Configuring Reporting and Bindings.", settings.trace, get_LOG_DEBUG()) //allow 30 minutes without receiving on/off state - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - return zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) + // configure reporting of active power - zigbee.configureReporting(0x0B04, 0x050B, 0x29, 30, 599, 0x64) + //configure reporting of on/off + return zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) + //configure reporting of on/off + zigbee.configureReporting(0x0B04, 0x050B, 0x29, 5, 300, 0x05) + // configure reporting of active power zigbee.readAttribute(0x0006, 0x0000) + //read on/off zigbee.readAttribute(0x0B04, 0x050B) //read active power } @@ -130,35 +128,25 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/devicetypes/sinope-technologies/sw2500zb-sinope-switch.src/sw2500zb-sinope-switch.groovy b/devicetypes/sinope-technologies/sw2500zb-sinope-switch.src/sw2500zb-sinope-switch.groovy index e3285645a05..23dca081ba7 100644 --- a/devicetypes/sinope-technologies/sw2500zb-sinope-switch.src/sw2500zb-sinope-switch.groovy +++ b/devicetypes/sinope-technologies/sw2500zb-sinope-switch.src/sw2500zb-sinope-switch.groovy @@ -1,7 +1,6 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1.3.0 SVN-571 * 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. @@ -12,8 +11,8 @@ metadata { preferences { input("LedIntensityParam", "number", title:"Indicator light intensity (1..100) (default: blank)", range:"1..100", description:"optional") input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") } definition (name: "SW2500ZB Sinope Switch", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.switch") @@ -25,7 +24,7 @@ metadata { capability "Health Check" - fingerprint manufacturer: "Sinope Technologies", model: "SW2500ZB", deviceJoinName: "SW2500ZB" + fingerprint manufacturer: "Sinope Technologies", model: "SW2500ZB", deviceJoinName: "Sinope Switch" //SW2500ZB } tiles(scale: 2) @@ -58,7 +57,7 @@ def parse(String description) { traceEvent(settings.logFilter, "Event: $event", settings.trace, get_LOG_DEBUG()) sendEvent(event) - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } else { @@ -123,8 +122,8 @@ def configure() { traceEvent(settings.logFilter, "Configuring Reporting and Bindings", settings.trace, get_LOG_DEBUG()) - //allow 30 min without receiving on/off report - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + //allow 5 min without receiving on/off report + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) return zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, 600, null) + zigbee.readAttribute(0x0006, 0x0000) @@ -152,36 +151,26 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } } diff --git a/devicetypes/sinope-technologies/th1123zb-th1124zb-sinope-thermostat.src/th1123zb-th1124zb-sinope-thermostat.groovy b/devicetypes/sinope-technologies/th1123zb-th1124zb-sinope-thermostat.src/th1123zb-th1124zb-sinope-thermostat.groovy index b089b56ce1d..ed5b31571b2 100644 --- a/devicetypes/sinope-technologies/th1123zb-th1124zb-sinope-thermostat.src/th1123zb-th1124zb-sinope-thermostat.groovy +++ b/devicetypes/sinope-technologies/th1123zb-th1124zb-sinope-thermostat.src/th1123zb-th1124zb-sinope-thermostat.groovy @@ -1,50 +1,49 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 -SVN-571 +Copyright Sinopé Technologies +1.3.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. **/ -preferences { - input("BacklightAutoDimParam", "enum", title:"Backlight setting (default: sensing)", description: "On Demand or Sensing", options: ["On Demand", "Sensing"], multiple: false, required: false) - input("DisableOutdorTemperatureParam", "bool", title: "disable outdoor temperature", description: "Set it to true to Disable outdoor temperature on the thermostat") - input("keyboardLockParam", "bool", title: "enable the lock", description: "Set to true to enable the lock on the thermostat") - input("trace", "bool", title: "Trace", description:"Set it to true to enable tracing") - input("logFilter", "number", title: "(1=ERROR only,2=<1+WARNING>,3=<2+INFO>,4=<3+DEBUG>,5=<4+TRACE>)", range: "1..5", - description: "optional") -} - metadata { - + preferences { + input("backlightAutoDimParam", "enum", title:"Backlight setting (Default: Always ON)", multiple: false, required: false, options: ["On Demand", "Always ON"], + description: "On Demand or Always ON") + input("disableOutdorTemperatureParam", "enum", title: "Secondary display (Default: Outside temp.)", multiple: false, required: false, options: ["Setpoint", "Outside temp."], + description: "Information displayed in the secondary zone of the device") + input("keyboardLockParam", "enum", title: "Keypad lock (Default: Unlock)", multiple: false, required: false, options: ["Lock", "Unlock"], + description: "Enable or disable the device's buttons") + input("timeFormatParam", "enum", title:"Time Format (Default: 24h)", options:["12h AM/PM","24h"], multiple: false, required: false, + description: "Time format displayed by the device.") + input("trace", "bool", title: "Trace", + description:"Set it to true to enable tracing") + } definition(name: "TH1123ZB-TH1124ZB Sinope Thermostat", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.thermostat") { - capability "thermostatHeatingSetpoint" - capability "thermostatMode" - capability "thermostatOperatingState" - capability "thermostatSetpoint" - capability "Actuator" capability "Temperature Measurement" + capability "Thermostat" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Actuator" capability "Configuration" capability "Refresh" - capability "lock" - capability "Health check" + capability "Health check" + capability "Sensor" - attribute "temperatureDisplayMode", "enum", ["Deg_C", "Deg_F"] attribute "heatingSetpointRangeHigh", "number" attribute "heatingSetpointRangeLow", "number" attribute "heatingSetpointRange", "VECTOR3" - attribute "outdoorTemp", "string" - attribute "verboseTrace", "string" + attribute "outdoorTemp", "number" + attribute "temperatureUnit", "string" command "heatLevelUp" command "heatLevelDown" - fingerprint manufacturer: "Sinope Technologies", model: "TH1123ZB", deviceJoinName: "Sinope TH1123ZB Thermostat" + fingerprint manufacturer: "Sinope Technologies", model: "TH1123ZB", deviceJoinName: "Sinope Thermostat" //Sinope TH1123ZB Thermostat - fingerprint manufacturer: "Sinope Technologies", model: "TH1124ZB", deviceJoinName: "Sinope TH1124ZB Thermostat" + fingerprint manufacturer: "Sinope Technologies", model: "TH1124ZB", deviceJoinName: "Sinope Thermostat" //Sinope TH1124ZB Thermostat } - + simulator { } //-------------------------------------------------------------------------------------------------------- tiles(scale: 2) { @@ -57,15 +56,14 @@ metadata { attributeState("VALUE_DOWN", action: "heatLevelDown") } tileAttribute("device.heatingDemand", key: "SECONDARY_CONTROL") { - attributeState("default", label: '${currentValue}%', unit: "%") + attributeState("default", label: '${currentValue}%', unit: "%", icon:"st.Weather.weather2") } tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { attributeState("idle", backgroundColor: "#44b621") attributeState("heating", backgroundColor: "#ffa81e") - attributeState("cooling", backgroundColor: "#269bd2") } tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { - attributeState("default", label: '${currentValue}', unit: "dF") + attributeState("heatingSetpoint", label: '${currentValue}°', unit:"dF", range: "(5..30)", defaultState: true) } } //-- Value Tiles ------------------------------------------------------------------------------------------- @@ -76,18 +74,17 @@ metadata { //-- Standard Tiles ---------------------------------------------------------------------------------------- - standardTile("thermostatMode", "device.thermostatMode", inactiveLabel: false, height: 2, width: 2, decoration: "flat") { + standardTile("mode", "device.thermostatMode", inactiveLabel: false, height: 2, width: 2, decoration: "flat") { state "off", label: '', action: "heat", icon: "st.thermostat.heating-cooling-off" state "heat", label: '', action: "off", icon: "st.thermostat.heat", defaultState: true } - standardTile("refresh", "device.temperature", inactiveLabel: false, width: 2, height: 2, decoration: "flat") { + standardTile("refresh", "device.refresh", inactiveLabel: false, width: 2, height: 2, decoration: "flat") { state "default", action: "refresh.refresh", icon: "st.secondary.refresh" } - //-- Main & Details ---------------------------------------------------------------------------------------- - controlTile("heatingSetpointSlider", "device.heatingSetpoint", "slider", + controlTile("heatingSetpoint", "device.heatingSetpoint", "slider", sliderType: "HEATING", debouncePeriod: 1500, range: "device.heatingSetpointRange", @@ -97,44 +94,36 @@ metadata { label:'${currentValue}${unit}', backgroundColor: "#E86D13" } + //-- Main & Details ---------------------------------------------------------------------------------------- main("thermostatMulti") - details(["thermostatMulti", - "heatingSetpointSlider", - "thermostatMode", - "refresh" - ]) + details(["thermostatMulti", "heatingSetpoint", "mode", "refresh"]) } } -def getBackgroundColors() { - def results - if (state?.scale == 'C') { - // Celsius Color Range - results = [ - [value: 0, color: "#153591"], - [value: 7, color: "#1e9cbb"], - [value: 15, color: "#90d2a7"], - [value: 23, color: "#44b621"], - [value: 29, color: "#f1d801"], - [value: 35, color: "#d04e00"], - [value: 37, color: "#bc2323"] - ] - } else { - results = - // Fahrenheit Color Range - [ - [value: 31, color: "#153591"], - [value: 44, color: "#1e9cbb"], - [value: 59, color: "#90d2a7"], - [value: 74, color: "#44b621"], - [value: 84, color: "#f1d801"], - [value: 95, color: "#d04e00"], - [value: 96, color: "#bc2323"] - ] - } - return results +def getSupportedThermostatModes() { + ["heat", "off"] +} + +def getHeatingSetpointRange() { + (temperatureScale == "C") ? [5.0, 30.0] : [41, 86] +} +def getThermostatSetpointRange() { + heatingSetpointRange +} + +def getSetpointStep() { + (getTemperatureScale() == "C") ? 0.5 : 1.0 +} + +def configureSupportedRanges() { + sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false) + + sendEvent(name: "thermostatSetpointRange", value: heatingSetpointRange, scale: temperatureScale, displayed: false) + + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: temperatureScale, displayed: false) + } //-- Installation ---------------------------------------------------------------------------------------- @@ -147,7 +136,7 @@ def installed() { def updated() { - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 5000) { + if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 1000) { state.updatedLastRanAt = now() traceEvent(settings.logFilter, "updated>Device is now updated", settings.trace) @@ -165,12 +154,24 @@ def configure() { traceEvent(settings.logFilter, "Configuring Reporting and Bindings", settings.trace, get_LOG_DEBUG()) - //allow 30 min without receiving temperature report - return sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + def cmds = [] + + cmds += zigbee.configureReporting(0x0201, 0x0000, 0x29, 19, 301, 50) //local temperature + cmds += zigbee.configureReporting(0x0201, 0x0008, 0x0020, 4, 300, 10) //heating demand + cmds += zigbee.configureReporting(0x0201, 0x0012, 0x0029, 15, 302, 40) //occupied heating setpoint + + + if(cmds) + { + sendZigbeeCommands(cmds) + } + + //allow 5 min without receiving temperature report + return sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } void initialize() { - state?.scale = getTemperatureScale() + state?.scale = temperatureScale runIn(2,refresh) runEvery15Minutes(refresh_misc) @@ -178,21 +179,15 @@ void initialize() { def supportedThermostatModes = ['off', 'heat'] state?.supportedThermostatModes = supportedThermostatModes sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes) - if(state?.scale == 'C') - { - sendEvent(name: "heatingSetpointRangeLow", value: 5.0, scale: scale) - sendEvent(name: "heatingSetpointRangeHigh", value: 30.0, scale: scale) - } - else if(state?.scale == 'F') - { - sendEvent(name: "heatingSetpointRangeLow", value: 41, scale: scale) - sendEvent(name: "heatingSetpointRangeHigh", value: 86, scale: scale) - } - sendEvent(name: "lock", value: "unlocked") + configureSupportedRanges(); + + refresh(); } def ping() { - refresh() + // refresh() + def cmds = zigbee.readAttribute(0x0201, 0x0000); + sendZigbeeCommands(cmds) } def uninstalled() { @@ -204,12 +199,12 @@ def uninstalled() { // parse events into attributes def parse(String description) { def result = [] - def scale = getTemperatureScale() + def scale = state?.scale state?.scale = scale traceEvent(settings.logFilter, "parse>Description :( $description )", settings.trace) def cluster = zigbee.parse(description) traceEvent(settings.logFilter, "parse>Cluster : $cluster", settings.trace) - if (description?.startsWith("read attr -")) { + if (description?.startsWith("read attr -") || description?.startsWith("write attr -")) { def descMap = zigbee.parseDescriptionAsMap(description) result += createCustomMap(descMap) if(descMap.additionalAttrs){ @@ -229,54 +224,56 @@ def parse(String description) { def createCustomMap(descMap){ def result = null def map = [: ] - def scale = getTemperatureScale() + def scale = temperatureScale if (descMap.cluster == "0201" && descMap.attrId == "0000") { map.name = "temperature" map.value = getTemperatureValue(descMap.value) - sendEvent(name: map.name, value: map.value, unit: scale) + map.unit = scale traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}", settings.trace) - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + //allow 5 min without receiving temperature report + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } else if (descMap.cluster == "0201" && descMap.attrId == "0008") { map.name = "heatingDemand" map.value = getHeatingDemand(descMap.value) - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}") + def operatingState = (map.value.toInteger() < 10) ? "idle" : "heating" sendEvent(name: "thermostatOperatingState", value: operatingState) traceEvent(settings.logFilter,"thermostatOperatingState: ${operatingState}", settings.trace) } else if (descMap.cluster == "0201" && descMap.attrId == "0012") { + configureSupportedRanges(); map.name = "heatingSetpoint" map.value = getTemperatureValue(descMap.value, true) - sendEvent(name: map.name, value: map.value, unit: scale) + map.unit = scale traceEvent(settings.logFilter, "parse>OCCUPY: ${map.name}: ${map.value}, scale: ${scale} ", settings.trace) } - else if (descMap.cluster == "0201" && descMap.attrId == "0014") { + else if (descMap.cluster == "0201" && descMap.attrId == "0014") { // UnpccupiedHeatingSetpoint + configureSupportedRanges(); map.name = "heatingSetpoint" map.value = getTemperatureValue(descMap.value, true) - sendEvent(name: map.name, value: map.value, unit: scale) + map.unit = scale traceEvent(settings.logFilter, "parse>UNOCCUPY: ${map.name}: ${map.value}", settings.trace) } else if (descMap.cluster == "0201" && descMap.attrId == "001c") { map.name = "thermostatMode" map.value = getModeMap()[descMap.value] - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}", settings.trace) } - else if (descMap.cluster == "0204" && descMap.attrId == "0001") { - map.name = "lock" - map.value = getLockMap()[descMap.value] - sendEvent(name: map.name, value: map.value) - traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}", settings.trace) + else{ + result = "{cluster:"+descMap.cluster+", attrId:"+descMap.attrId+",value:"+descMap.value+"}"; } + if(map){ + result = createEvent(map); + } return result } //-- Temperature ----------------------------------------------------------------------------------------- def getTemperatureValue(value, doRounding = false) { - def scale = state?.scale + def scale = temperatureScale if (value != null) { double celsius = (Integer.parseInt(value, 16) / 100).toDouble() if (scale == "C") { @@ -316,7 +313,7 @@ def getHeatingDemand(value) { //-- Heating Setpoint ------------------------------------------------------------------------------------ def heatLevelUp() { - def scale = getTemperatureScale() + def scale = temperatureScale double nextLevel if (scale == 'C') { @@ -334,7 +331,7 @@ def heatLevelUp() { } def heatLevelDown() { - def scale = getTemperatureScale() + def scale = temperatureScale double nextLevel if (scale == 'C') { @@ -351,7 +348,7 @@ def heatLevelDown() { } def setHeatingSetpoint(degrees) { - def scale = getTemperatureScale() + def scale = temperatureScale degrees = checkTemperature(degrees) def degreesDouble = degrees as Double String tempValueString @@ -360,30 +357,22 @@ def setHeatingSetpoint(degrees) { } else { tempValueString = String.format('%2d', degreesDouble.intValue()) } - sendEvent(name: "heatingSetpoint", value: tempValueString, unit: scale) traceEvent(settings.logFilter, "setHeatingSetpoint> new setPoint: $tempValueString", settings.trace) def celsius = (scale == "C") ? degreesDouble : (fahrenheitToCelsius(degreesDouble) as Double).round(1) def cmds = [] cmds += zigbee.writeAttribute(0x201, 0x12, 0x29, hex(celsius * 100)) + cmds += zigbee.readAttribute(0x0201, 0x0012) sendZigbeeCommands(cmds) } -//-- Thermostat and Fan Modes ------------------------------------------------------------------------------------- +//-- Thermostat Modes ------------------------------------------------------------------------------------- void off() { setThermostatMode('off') } -void auto() { - setThermostatMode('auto') -} + void heat() { setThermostatMode('heat') } -void emergencyHeat() { - setThermostatMode('heat') -} -void cool() { - setThermostatMode('cool') -} def modes() { @@ -397,20 +386,9 @@ def getModeMap() { ] } -def getSupportedThermostatModes() { - - if (!state?.supportedThermostatModes) { - state?.supportedThermostatModes = (device.currentValue("supportedThermostatModes")) ? - device.currentValue("supportedThermostatModes").toString().minus('[').minus(']').tokenize(',') : ['off', 'heat'] - } - return state?.supportedThermostatModes -} - def setThermostatMode(mode) { traceEvent(settings.logFilter, "setThermostatMode>switching thermostatMode", settings.trace) mode = mode?.toLowerCase() - def supportedThermostatModes = getSupportedThermostatModes() - if (mode in supportedThermostatModes) { "mode_$mode" () } else { @@ -420,20 +398,18 @@ def setThermostatMode(mode) { def mode_off() { traceEvent(settings.logFilter, "off>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "off", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 0) - cmds += zigbee.readAttribute(0x0201, 0x0008) + cmds += zigbee.readAttribute(0x0201, 0x001C) sendZigbeeCommands(cmds) traceEvent(settings.logFilter, "off>end", settings.trace) } def mode_heat() { traceEvent(settings.logFilter, "heat>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "heat", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 4) - cmds += zigbee.readAttribute(0x0201, 0x0008) + cmds += zigbee.readAttribute(0x0201, 0x001C) sendZigbeeCommands(cmds) traceEvent(settings.logFilter, "heat>end", settings.trace) } @@ -451,74 +427,56 @@ def getLockMap() { ] } -def unlock() { - traceEvent(settings.logFilter, "unlock>begin", settings.trace) - sendEvent(name: "lock", value: "unlocked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) - sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "unlock>end", settings.trace) -} - -def lock() { - traceEvent(settings.logFilter, "lock>begin", settings.trace) - sendEvent(name: "lock", value: "locked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) - sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "lock>end", settings.trace) -} - //---misc-------------------------------------------------------------------------------------------------------- def refresh() { - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 20000) { - state.updatedLastRanAt = now() - - state?.scale = getTemperatureScale() - traceEvent(settings.logFilter, "refresh>scale=${state.scale}", settings.trace) - - def cmds = [] - + if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 5000) { + def cmds = [] + + state.updatedLastRanAt = now() cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature - cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint - cmds += zigbee.readAttribute(0x0201, 0x0008) // Rd thermostat PI heating demand - cmds += zigbee.readAttribute(0x0201, 0x001C) // Rd thermostat System Mode - cmds += zigbee.readAttribute(0x0204, 0x0001) // Rd thermostat Keypad lock - - cmds += zigbee.configureReporting(0x0201, 0x0000, 0x29, 19, 301, 50) //local temperature - cmds += zigbee.configureReporting(0x0201, 0x0008, 0x0020, 4, 300, 10) //heating demand - cmds += zigbee.configureReporting(0x0201, 0x0012, 0x0029, 15, 302, 40) //occupied heating setpoint - + cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint + cmds += zigbee.readAttribute(0x0201, 0x0008) // Rd thermostat PI heating demand + cmds += zigbee.readAttribute(0x0201, 0x001C) // Rd thermostat System Mode + cmds += zigbee.readAttribute(0x0204, 0x0001) // Rd thermostat Keypad lock + sendZigbeeCommands(cmds) - refresh_misc() + refresh_misc() } else { - traceEvent(settings.logFilter, "updated(): Ran within last 20 seconds so aborting", settings.trace, get_LOG_TRACE()) + traceEvent(settings.logFilter, "updated(): Ran within last 5 seconds so aborting", settings.trace, get_LOG_TRACE()) } } void refresh_misc() { + + def constraint = ["heating","idle"] def weather = get_weather() - traceEvent(settings.logFilter,"refresh_misc>begin, settings.DisableOutdorTemperatureParam=${settings.DisableOutdorTemperatureParam}, weather=$weather", settings.trace) + traceEvent(settings.logFilter,"refresh_misc>begin, settings.disableOutdorTemperatureParam=${settings.disableOutdorTemperatureParam}, weather=$weather", settings.trace) def cmds=[] - - if (weather) { + state?.scale = temperatureScale + + traceEvent(settings.logFilter, "refresh>scale=${state.scale}", settings.trace) + + if (weather || weather == 0) { double tempValue int outdoorTemp = weather.toInteger() - if(state?.scale == 'F') + if(temperatureScale == 'F') {//the value sent to the thermostat must be in C //the thermostat make the conversion to F outdoorTemp = fahrenheitToCelsius(outdoorTemp).toDouble().round() } int outdoorTempValue int outdoorTempToSend - - if(!settings.DisableOutdorTemperatureParam) + if(disableOutdorTemperatureParam == "Setpoint") { + //delete outdoorTemp + cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, 0x8000) + } + else { - cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 10800)//set the outdoor temperature timeout to 3 hours + cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 10800)//set the outdoor temperature timeout to 3 hours if (outdoorTemp < 0) { outdoorTempValue = -outdoorTemp*100 - 65536 outdoorTempValue = -outdoorTempValue @@ -532,12 +490,6 @@ void refresh_misc() { cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, outdoorTempToSend, [mfgCode: 0x119C]) } } - else - {//delete outdoorTemp - //the outdoor temperature cannot be directly erased from the thermostat. - //to erase it rapidly, the external temperature timeout must be set to the minimal value (30sec) - cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 30)//set the outdoor temperature timeout to 30sec - } def mytimezone = location.getTimeZone() long dstSavings = 0 @@ -551,51 +503,41 @@ void refresh_misc() { } - if(BacklightAutoDimParam == "On Demand"){ //Backlight when needed + if(backlightAutoDimParam == "On Demand"){ //Backlight when needed traceEvent(settings.logFilter,"Backlight on press",settings.trace) cmds += zigbee.writeAttribute(0x0201, 0x0402, 0x30, 0x0000) } else{ //Backlight sensing - traceEvent(settings.logFilter,"Backlight Sensing",settings.trace) + traceEvent(settings.logFilter,"Backlight Always ON",settings.trace) cmds += zigbee.writeAttribute(0x0201, 0x0402, 0x30, 0x0001) } traceEvent(settings.logFilter,"keyboardLockParam: ${keyboardLockParam}",settings.trace) - if(keyboardLockParam != true){ //unlock - traceEvent(settings.logFilter,"unlock",settings.trace) - unlock() - } - else{ //lock + if(keyboardLockParam == "Lock"){ //lock traceEvent(settings.logFilter,"lock",settings.trace) - lock() - } + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) + } + else{ //unlock + traceEvent(settings.logFilter,"unlock",settings.trace) + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) + } + + if(timeFormatParam == "12h AM/PM"){//12h AM/PM + traceEvent(settings.logFilter,"Set to 12h AM/PM",settings.trace) + cmds += zigbee.writeAttribute(0xFF01, 0x0114, 0x30, 0x0001) + } + else{//24h + traceEvent(settings.logFilter,"Set to 24h",settings.trace) + cmds += zigbee.writeAttribute(0xFF01, 0x0114, 0x30, 0x0000) + } traceEvent(settings.logFilter,"refresh_misc> about to refresh other misc, scale=${state.scale}", settings.trace) - - if (state?.scale == 'C') { + if (state?.scale == 'C') { cmds += zigbee.writeAttribute(0x0204, 0x0000, 0x30, 0) // Wr °C on thermostat display } else { cmds += zigbee.writeAttribute(0x0204, 0x0000, 0x30, 1) // Wr °F on thermostat display } - - def heatingSetpointRangeHigh - def heatingSetpointRangeLow - if(state?.scale == 'C') - { - heatingSetpointRangeLow = 5.0 - heatingSetpointRangeHigh = 30.0 - } - else if(state?.scale == 'F') - { - heatingSetpointRangeLow = 41 - heatingSetpointRangeHigh = 86 - } - sendEvent(name: "heatingSetpointRangeLow", value: heatingSetpointRangeLow, scale: scale) - sendEvent(name: "heatingSetpointRangeHigh", value: heatingSetpointRangeHigh, scale: scale) - def low = heatingSetpointRangeLow.toFloat().round(1) - def high = heatingSetpointRangeHigh.toFloat().round(1) - def heatingSetpointRange= [low,high] - sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) + traceEvent(settings.logFilter,"refresh_misc>end", settings.trace) if(cmds) @@ -607,7 +549,7 @@ void refresh_misc() { //-- Private functions ----------------------------------------------------------------------------------- -void sendZigbeeCommands(cmds, delay = 1000) { +void sendZigbeeCommands(cmds, delay = 250) { cmds.removeAll { it.startsWith("delay") } // convert each command into a HubAction cmds = cmds.collect { new physicalgraph.device.HubAction(it) } @@ -616,7 +558,7 @@ void sendZigbeeCommands(cmds, delay = 1000) { private def checkTemperature(def number) { - def scale = getTemperatureScale() + def scale = temperatureScale if(scale == 'F') { if(number < 41) @@ -700,35 +642,25 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/devicetypes/sinope-technologies/th1300zb-sinope-thermostat.src/th1300zb-sinope-thermostat.groovy b/devicetypes/sinope-technologies/th1300zb-sinope-thermostat.src/th1300zb-sinope-thermostat.groovy index 5b1d91114b0..948359d6807 100644 --- a/devicetypes/sinope-technologies/th1300zb-sinope-thermostat.src/th1300zb-sinope-thermostat.groovy +++ b/devicetypes/sinope-technologies/th1300zb-sinope-thermostat.src/th1300zb-sinope-thermostat.groovy @@ -1,58 +1,61 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1.3.1 SVN-571 * 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. **/ metadata { - -preferences { - input("AirFloorModeParam", "enum", title: "Control mode (Default: Floor)", description:"Control mode using the floor or ambient temperature.", options: ["Ambient", "Floor"], multiple: false, required: false) - input("BacklightAutoDimParam", "enum", title:"Backlight setting (Default: Sensing)", description: "On Demand or Sensing", options: ["Sensing", "On Demand"], multiple: false, required: false) - input("KbdLockParam", "enum", title: "Keypad lock (Default: Unlocked)", description: "Enable or disable the device's buttons.",options: ["Lock", "Unlock"], multiple: false, required: false) - input("TimeFormatParam", "enum", title:"Time Format (Default: 24h)", description: "Time format displayed by the device.", options:["24h", "12h AM/PM"], multiple: false, required: false) - input("DisableOutdorTemperatureParam", "bool", title: "enable/disable outdoor temperature", description: "Set it to true to Disable outdoor temperature on the thermostat") - input("FloorSensorTypeParam", "enum", title:"Probe type (Default: 10k)", description: "Choose probe type.", options: ["10k", "12k"], multiple: false, required: false) - input("FloorMaxAirTemperatureParam", "number", title:"Ambient limit (5C to 36C / 41F to 96)", range:("5..96"), - description: "The maximum ambient temperature limit when in floor control mode.", required: false) - input("FloorLimitMinParam", "number", title:"Floor low limit (5C to 36C / 41F to 96F)", range:("5..96"), description: "The minimum temperature limit of the floor when in ambient control mode.", required: false) - input("FloorLimitMaxParam", "number", title:"Floor high limit (5C to 36C / 41F to 96F)", range:("5..96"), description: "The maximum temperature limit of the floor when in ambient control mode.", required: false) - input("AuxLoadParam", "number", title:"Auxiliary load value (Default: 0)", range:("0..65535"), - description: "Enter the power in watts of the heating element connected to the auxiliary output.", required: false) - input("trace", "bool", title: "Trace (Only for debugging)", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") -} - - + preferences { + input("AirFloorModeParam", "enum", title: "Control mode (Default: Floor)", + description:"Control mode using the floor or ambient temperature.", options: ["Ambient", "Floor"], multiple: false, required: false) + input("BacklightAutoDimParam", "enum", title:"Backlight setting (Default: Always ON)", + description: "On Demand or Always ON", options: ["On Demand", "Always ON"], multiple: false, required: false) + input("KbdLockParam", "enum", title: "Keypad lock (Default: Unlocked)", + description: "Enable or disable the device's buttons.",options: ["Lock", "Unlock"], multiple: false, required: false) + input("TimeFormatParam", "enum", title:"Time Format (Default: 24h)", + description: "Time format displayed by the device.", options:["12h AM/PM", "24h"], multiple: false, required: false) + input("DisableOutdorTemperatureParam", "enum", title: "Secondary display (Default: Outside temp.)", multiple: false, required: false, options: ["Setpoint", "Outside temp."], + description: "Information displayed in the secondary zone of the device") + input("FloorSensorTypeParam", "enum", title:"Probe type (Default: 10k)", + description: "Choose floor sensors probe. The floor sensor provided with the thermostats are 10K.", options: ["10k", "12k"], multiple: false, required: false) + + input("FloorMaxAirTemperatureParam", "number", title:"Ambient limit in Celsius (5C to 36C)", range: "5..36", + description: "The maximum ambient temperature limit in Celsius when in floor control mode.", required: false) + input("FloorLimitMinParam", "number", title:"Floor low limit in Celsius (5C to 34C)", range: "5..34", + description: "The minimum temperature limit in Celsius of the floor when in ambient control mode.", required: false) + input("FloorLimitMaxParam", "number", title:"Floor high limit in Celsius (7C to 36C)", range: "7..36", + description: "The maximum temperature limit of the floor in Celsius when in ambient control mode.", required: false) + // input("AuxLoadParam", "number", title:"Auxiliary load value (Default: 0)", range:("0..65535"), + // description: "Enter the power in watts of the heating element connected to the auxiliary output.", required: false) + input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + } definition(name: "TH1300ZB Sinope Thermostat", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.thermostat") { - capability "thermostatHeatingSetpoint" - capability "thermostatMode" - capability "thermostatOperatingState" - capability "thermostatSetpoint" - capability "Actuator" capability "Temperature Measurement" + capability "Thermostat" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Actuator" capability "Configuration" + capability "Health check" capability "Refresh" capability "Sensor" - capability "lock" - attribute "temperatureDisplayMode", "enum", ["Deg_C", "Deg_F"] - attribute "occupancyStatus", "enum", ["unoccupy", "occupy"] attribute "outdoorTemp", "string" attribute "heatingSetpointRange", "VECTOR3" - attribute "verboseTrace", "string" attribute "gfciStatus", "enum", ["OK", "error"] attribute "floorLimitStatus", "enum", ["OK", "floorLimitLowReached", "floorLimitMaxReached", "floorAirLimitLowReached", "floorAirLimitMaxReached"] command "heatLevelUp" command "heatLevelDown" - fingerprint manufacturer: "Sinope Technologies", model: "TH1300ZB", deviceJoinName: "Sinope TH1300ZB Thermostat" + fingerprint manufacturer: "Sinope Technologies", model: "TH1300ZB", deviceJoinName: "Sinope Thermostat" //Sinope TH1300ZB Thermostat } + simulator { } //-------------------------------------------------------------------------------------------------------- tiles(scale: 2) { @@ -65,16 +68,12 @@ preferences { attributeState("VALUE_DOWN", action: "heatLevelDown") } tileAttribute("device.heatingDemand", key: "SECONDARY_CONTROL") { - attributeState("default", label: '${currentValue}%', unit: "%") + attributeState("default", label: '${currentValue}%', unit: "%", icon:"st.Weather.weather2") } tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { attributeState("idle", backgroundColor: "#44b621") attributeState("heating", backgroundColor: "#ffa81e") } - tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { - attributeState("off", label: '${name}') - attributeState("heat", label: '${name}') - } tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { attributeState("default", label: '${currentValue}', unit: "dF") } @@ -110,46 +109,28 @@ preferences { //-- Main & Details ---------------------------------------------------------------------------------------- main("thermostatMulti") - details(["thermostatMulti", - "heatingSetpointSlider", - "thermostatMode", - "gfciStatus", - "floorLimitStatus", - "refresh" - ]) + details(["thermostatMulti", "heatingSetpointSlider", "thermostatMode", "gfciStatus", "floorLimitStatus", "refresh"]) } } -def getBackgroundColors() { - def results - if (state?.scale == 'C') { - // Celsius Color Range - results = [ - [value: 0, color: "#153591"], - [value: 7, color: "#1e9cbb"], - [value: 15, color: "#90d2a7"], - [value: 23, color: "#44b621"], - [value: 29, color: "#f1d801"], - [value: 35, color: "#d04e00"], - [value: 37, color: "#bc2323"] - ] - } else { - results = - // Fahrenheit Color Range - [ - [value: 31, color: "#153591"], - [value: 44, color: "#1e9cbb"], - [value: 59, color: "#90d2a7"], - [value: 74, color: "#44b621"], - [value: 84, color: "#f1d801"], - [value: 95, color: "#d04e00"], - [value: 96, color: "#bc2323"] - ] - } - return results - +def getThermostatSetpointRange() { + (getTemperatureScale() == "C") ? [5, 36] : [41, 96] } +def getHeatingSetpointRange() { + thermostatSetpointRange +} + +def getSupportedThermostatModes() { + ["heat", "off"] +} + +def configureSupportedRanges() { + sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false) + // These are part of the deprecated Thermostat capability. Remove these when that capability is removed. + sendEvent(name: "thermostatSetpointRange", value: thermostatSetpointRange, displayed: false) + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, displayed: false) +} //-- Installation ---------------------------------------------------------------------------------------- @@ -161,8 +142,7 @@ def installed() { } def updated() { - - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 15000) { + if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 1000) { state.updatedLastRanAt = now() def cmds = [] @@ -175,25 +155,24 @@ def updated() { runEvery15Minutes(refresh_misc) - if(AirFloorModeParam == "Ambient"){//Air mode - traceEvent(settings.logFilter,"Set to Ambient mode",settings.trace) - cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0001) - } - else{//Floor mode - traceEvent(settings.logFilter,"Set to Floor mode",settings.trace) - cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0002) - } - - if(KbdLockParam == "Lock"){ + if(KbdLockParam == "Lock" || KbdLockParam == '0'){ traceEvent(settings.logFilter,"device lock",settings.trace) - lock() + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) } else{ traceEvent(settings.logFilter,"device unlock",settings.trace) - unlock() + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) + } + if(AirFloorModeParam == "Floor" || AirFloorModeParam == '1'){//Floor mode + traceEvent(settings.logFilter,"Set to Floor mode",settings.trace) + cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0002) + } + else{//Air mode + traceEvent(settings.logFilter,"Set to Floor mode",settings.trace) + cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0001) } - if(TimeFormatParam == "12h AM/PM"){//12h AM/PM + if(TimeFormatParam == "12h AM/PM" || TimeFormatParam == '0'){//12h AM/PM traceEvent(settings.logFilter,"Set to 12h AM/PM",settings.trace) cmds += zigbee.writeAttribute(0xFF01, 0x0114, 0x30, 0x0001) } @@ -202,7 +181,7 @@ def updated() { cmds += zigbee.writeAttribute(0xFF01, 0x0114, 0x30, 0x0000) } - if(BacklightAutoDimParam == "On Demand"){ //Backlight when needed + if(BacklightAutoDimParam == "On Demand" || BacklightAutoDimParam == '0'){ //Backlight when needed traceEvent(settings.logFilter,"Backlight on press",settings.trace) cmds += zigbee.writeAttribute(0x0201, 0x0402, 0x30, 0x0000) } @@ -211,7 +190,7 @@ def updated() { cmds += zigbee.writeAttribute(0x0201, 0x0402, 0x30, 0x0001) } - if(FloorSensorTypeParam == "12k"){//sensor type = 12k + if(FloorSensorTypeParam == "12k" || FloorSensorTypeParam == '1'){//sensor type = 12k traceEvent(settings.logFilter,"Sensor type is 12k",settings.trace) cmds += zigbee.writeAttribute(0xFF01, 0x010B, 0x30, 0x0001) } @@ -225,15 +204,15 @@ def updated() { if(FloorMaxAirTemperatureParam){ def MaxAirTemperatureValue traceEvent(settings.logFilter,"FloorMaxAirTemperature param. scale: ${state?.scale}, Param value: ${FloorMaxAirTemperatureParam}",settings.trace) - if(state?.scale == 'F') + if(FloorMaxAirTemperatureParam >= 41) { - MaxAirTemperatureValue = fahrenheitToCelsius(FloorMaxAirTemperatureParam).toInteger() + MaxAirTemperatureValue = checkTemperature(FloorMaxAirTemperatureParam)//check if the temperature is between the maximum and minimum + MaxAirTemperatureValue = fahrenheitToCelsius(MaxAirTemperatureValue).toInteger() } else//state?.scale == 'C' { MaxAirTemperatureValue = FloorMaxAirTemperatureParam.toInteger() } - MaxAirTemperatureValue = checkTemperature(MaxAirTemperatureValue)//check if the temperature is between the maximum and minimum MaxAirTemperatureValue = MaxAirTemperatureValue * 100 cmds += zigbee.writeAttribute(0xFF01, 0x0108, 0x29, MaxAirTemperatureValue) } @@ -245,15 +224,15 @@ def updated() { if(FloorLimitMinParam){ def FloorLimitMinValue traceEvent(settings.logFilter,"FloorLimitMin param. scale: ${state?.scale}, Param value: ${FloorLimitMinParam}",settings.trace) - if(state?.scale == 'F') + if(FloorLimitMinParam >= 41) { - FloorLimitMinValue = fahrenheitToCelsius(FloorLimitMinParam).toInteger() + FloorLimitMinValue = checkTemperature(FloorLimitMinParam)//check if the temperature is between the maximum and minimum + FloorLimitMinValue = fahrenheitToCelsius(FloorLimitMinValue).toInteger() } else//state?.scale == 'C' { FloorLimitMinValue = FloorLimitMinParam.toInteger() } - FloorLimitMinValue = checkTemperature(FloorLimitMinValue)//check if the temperature is between the maximum and minimum FloorLimitMinValue = FloorLimitMinValue * 100 cmds += zigbee.writeAttribute(0xFF01, 0x0109, 0x29, FloorLimitMinValue) } @@ -265,15 +244,15 @@ def updated() { if(FloorLimitMaxParam){ def FloorLimitMaxValue traceEvent(settings.logFilter,"FloorLimitMax param. scale: ${state?.scale}, Param value: ${FloorLimitMaxParam}",settings.trace) - if(state?.scale == 'F') + if(FloorLimitMaxParam >= 45) { - FloorLimitMaxValue = fahrenheitToCelsius(FloorLimitMaxParam).toInteger() + FloorLimitMaxValue = checkTemperature(FloorLimitMaxParam)//check if the temperature is between the maximum and minimum + FloorLimitMaxValue = fahrenheitToCelsius(FloorLimitMaxValue).toInteger() } else//state?.scale == 'C' { FloorLimitMaxValue = FloorLimitMaxParam.toInteger() } - FloorLimitMaxValue = checkTemperature(FloorLimitMaxValue)//check if the temperature is between the maximum and minimum FloorLimitMaxValue = FloorLimitMaxValue * 100 cmds += zigbee.writeAttribute(0xFF01, 0x010A, 0x29, FloorLimitMaxValue) } @@ -299,41 +278,29 @@ def updated() { void initialize() { state?.scale = getTemperatureScale() - def supportedThermostatModes = ['off', 'heat'] state?.supportedThermostatModes = supportedThermostatModes - sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: (settings.trace ?: false)) + + configureSupportedRanges(); updated()//some thermostats values are not restored to a default value when disconnected. //executing the updated function make sure the thermostat parameters and the app parameters are in sync - if(state?.scale == 'C') - { - sendEvent(name: "heatingSetpointRange", value: [5.0, 36.0], scale: scale) - } - else if(state?.scale == 'F') - { - sendEvent(name: "heatingSetpointRangeLow", value: [41,96], scale: scale) - } - - sendEvent(name: "lock", value: "unlocked") - //for some reasons, the "runIn()" is not working in the "initialize()" of this driver. //to go around the problem, a read and a configuration is sent to each attribute required dor a good behaviour of the application def cmds = [] cmds += zigbee.readAttribute(0x0204, 0x0000) // Rd thermostat display mode if (state?.scale == 'C') { cmds += zigbee.writeAttribute(0x0204, 0x0000, 0x30, 0) // Wr °C on thermostat display - sendEvent(name: "heatingSetpointRange", value: [5,36], scale: state.scale) + sendEvent(name: "heatingSetpointRange", value: [5,36], scale: state?.scale) } else { cmds += zigbee.writeAttribute(0x0204, 0x0000, 0x30, 1) // Wr °F on thermostat display - sendEvent(name: "heatingSetpointRange", value: [41,96], scale: state.scale) + sendEvent(name: "heatingSetpointRange", value: [41,96], scale: state?.scale) } cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint cmds += zigbee.readAttribute(0x0201, 0x0008) // Rd thermostat PI heating demand cmds += zigbee.readAttribute(0x0201, 0x001C) // Rd thermostat System Mode - cmds += zigbee.readAttribute(0x0204, 0x0001) // Rd thermostat Keypad lockout cmds += zigbee.readAttribute(0xFF01, 0x0105) // Rd thermostat Control mode cmds += zigbee.readAttribute(0xFF01, 0x0115) // Rd GFCI status @@ -350,12 +317,14 @@ void initialize() { def configure() { traceEvent(settings.logFilter, "Configuring Reporting and Bindings", settings.trace, get_LOG_DEBUG()) - //allow 30 min without receiving on/off report - return sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + //allow 5 min without receiving temperature report + return sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } def ping() { - refresh() + def cmds = []; + cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature + sendZigbeeCommands(cmds) } def uninstalled() { @@ -393,10 +362,12 @@ def parse(String description) { def createCustomMap(descMap){ def result = null def map = [: ] - def scale = getTemperatureScale() + def scale = temperatureScale if (descMap.cluster == "0201" && descMap.attrId == "0000") { + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) map.name = "temperature" - map.value = getTemperatureValue(descMap.value, true) + map.value = getTemperatureValue(descMap.value, false) + map.unit = scale if(map.value > 158) {//if the value of the temperature is over 128C, it is considered an error with the temperature sensor map.value = "Sensor Error" @@ -414,13 +385,12 @@ def createCustomMap(descMap){ } } traceEvent(settings.logFilter, "parse>ACTUAL TEMP: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value, unit: scale) - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + //allow 5 min without receiving temperature report + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } else if (descMap.cluster == "0201" && descMap.attrId == "0008") { map.name = "heatingDemand" map.value = getHeatingDemand(descMap.value) - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}") def operatingState = (map.value.toInteger() < 10) ? "idle" : "heating" sendEvent(name: "thermostatOperatingState", value: operatingState) @@ -428,23 +398,18 @@ def createCustomMap(descMap){ } else if (descMap.cluster == "0201" && descMap.attrId == "0012") { + configureSupportedRanges(); + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) map.name = "heatingSetpoint" map.value = getTemperatureValue(descMap.value, true) - sendEvent(name: map.name, value: map.value, unit: scale) + map.unit = scale traceEvent(settings.logFilter, "parse>OCCUPY: ${map.name}: ${map.value}, scale: ${scale} ", settings.trace) } else if (descMap.cluster == "0201" && descMap.attrId == "001c") { map.name = "thermostatMode" map.value = getModeMap()[descMap.value] - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}", settings.trace) } - else if (descMap.cluster == "0204" && descMap.attrId == "0001") { - map.name = "keypadLockStatus" - map.value = getLockMap()[descMap.value] - traceEvent(settings.logFilter, "parse>KEYPAD LOCK STATUS: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value) - } else if (descMap.cluster == "FF01" && descMap.attrId == "010c") { map.name = "floorLimitStatus" if(descMap.value.toInteger() == 0){ @@ -458,19 +423,24 @@ def createCustomMap(descMap){ }else{ map.value = "floorAirLimitMaxReached" } + if(map.value != "OK"){ + log.warn map.value + } traceEvent(settings.logFilter, "parse>floorLimitStatus: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value) } else if (descMap.cluster == "FF01" && descMap.attrId == "0115") { map.name = "gfciStatus" if(descMap.value.toInteger() == 0){ map.value = "OK" }else if(descMap.value.toInteger() == 1){ + log.error("Ground Fault Circuit Interrupter (GFCI)") map.value = "error" } traceEvent(settings.logFilter, "parse>gfciStatus: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value) } + if(map){ + result = createEvent(map); + } return result } @@ -563,8 +533,6 @@ def setHeatingSetpoint(degrees) { } else { tempValueString = String.format('%2d', degreesDouble.intValue()) } - sendEvent("name": "heatingSetpoint", "value": tempValueString, scale: scale) - sendEvent("name": "thermostatSetpoint", "value": tempValueString, scale: scale) traceEvent(settings.logFilter, "setHeatingSetpoint> new setPoint: $tempValueString", settings.trace) def celsius = (scale == "C") ? degreesDouble : (fahrenheitToCelsius(degreesDouble) as Double).round(1) def cmds = [] @@ -601,19 +569,9 @@ def getModeMap() { ] } -def getSupportedThermostatModes() { - - if (!state?.supportedThermostatModes) { - state?.supportedThermostatModes = (device.currentValue("supportedThermostatModes")) ? - device.currentValue("supportedThermostatModes").toString().minus('[').minus(']').tokenize(',') : ['off', 'heat'] - } - return state?.supportedThermostatModes -} - def setThermostatMode(mode) { traceEvent(settings.logFilter, "setThermostatMode>switching thermostatMode", settings.trace) mode = mode?.toLowerCase() - def supportedThermostatModes = getSupportedThermostatModes() if (mode in supportedThermostatModes) { "mode_$mode" () @@ -624,79 +582,30 @@ def setThermostatMode(mode) { def mode_off() { traceEvent(settings.logFilter, "off>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "off", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 0) - cmds += zigbee.readAttribute(0x0201, 0x0008) - sendZigbeeCommands(cmds) + cmds += zigbee.readAttribute(0x0201, 0x001C) traceEvent(settings.logFilter, "off>end", settings.trace) + sendZigbeeCommands(cmds) } def mode_heat() { traceEvent(settings.logFilter, "heat>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "heat", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 4) - cmds += zigbee.readAttribute(0x0201, 0x0008) - sendZigbeeCommands(cmds) + cmds += zigbee.readAttribute(0x0201, 0x001C) traceEvent(settings.logFilter, "heat>end", settings.trace) -} -//-- Keypad Lock ----------------------------------------------------------------------------------------- - -def keypadLockLevel() { - ["unlock", "lock"] //only those level are used for the moment -} - -def getLockMap() { - [ - "00": "unlocked", - "01": "locked", - ] -} - -def unlock() { - traceEvent(settings.logFilter, "unlock>begin", settings.trace) - sendEvent(name: "lock", value: "unlocked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) - sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "unlock>end", settings.trace) -} - -def lock() { - traceEvent(settings.logFilter, "lock>begin", settings.trace) - sendEvent(name: "lock", value: "locked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "lock>end", settings.trace) } def refresh() { - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 20000) { // Check if last update > 20 sec + if (true || !state.updatedLastRanAt || now() >= state.updatedLastRanAt + 5000) { // Check if last update > 5 sec state.updatedLastRanAt = now() state?.scale = getTemperatureScale() traceEvent(settings.logFilter, "refresh>scale=${state.scale}", settings.trace) def cmds = [] - def heatingSetpointRangeHigh - def heatingSetpointRangeLow - if(state?.scale == 'C') - { - heatingSetpointRangeLow = 5.0 - heatingSetpointRangeHigh = 36.0 - } - else if(state?.scale == 'F') - { - heatingSetpointRangeLow = 41 - heatingSetpointRangeHigh = 96 - } - def low = heatingSetpointRangeLow.toFloat().round(1) - def high = heatingSetpointRangeHigh.toFloat().round(1) - def heatingSetpointRange= [low,high] - sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) - cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint cmds += zigbee.readAttribute(0x0201, 0x0008) // Rd thermostat PI heating demand @@ -707,12 +616,6 @@ def refresh() { cmds += zigbee.readAttribute(0xFF01, 0x0105) // Rd thermostat Control mode cmds += zigbee.readAttribute(0xFF01, 0x0115) // Rd GFCI status - cmds += zigbee.configureReporting(0x0201, 0x0000, 0x29, 19, 300, 25) // local temperature - cmds += zigbee.configureReporting(0x0201, 0x0008, 0x0020, 11, 301, 10) // heating demand - cmds += zigbee.configureReporting(0x0201, 0x0012, 0x0029, 8, 302, 40) // occupied heating setpoint - cmds += zigbee.configureReporting(0xFF01, 0x0115, 0x30, 10, 3600, 1) // report gfci status each hours - cmds += zigbee.configureReporting(0xFF01, 0x010C, 0x30, 10, 3600, 1) // floor limit status each hours - sendZigbeeCommands(cmds) refresh_misc() } @@ -735,8 +638,10 @@ void refresh_misc() { int outdoorTempValue int outdoorTempToSend - if(!settings.DisableOutdorTemperatureParam) - { + if(DisableOutdorTemperatureParam == "Setpoint" || DisableOutdorTemperatureParam == "0"){//delete outdoorTemp + cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, 0x8000) + } + else{ cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 10800)//set the outdoor temperature timeout to 3 hours if (outdoorTemp < 0) { outdoorTempValue = -outdoorTemp*100 - 65536 @@ -751,12 +656,6 @@ void refresh_misc() { cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, outdoorTempToSend, [mfgCode: 0x119C]) } } - else - {//delete outdoorTemp - //the outdoor temperature cannot be directly erased from the thermostat. - //to erase it rapidly, the external temperature timeout must be set to the minimal value (30sec) - cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 30)//set the outdoor temperature timeout to 30sec - } def mytimezone = location.getTimeZone() long dstSavings = 0 @@ -786,7 +685,7 @@ void refresh_misc() { //-- Private functions ----------------------------------------------------------------------------------- -void sendZigbeeCommands(cmds, delay = 1000) { +void sendZigbeeCommands(cmds, delay = 250) { cmds.removeAll { it.startsWith("delay") } // convert each command into a HubAction cmds = cmds.collect { new physicalgraph.device.HubAction(it) } @@ -879,35 +778,25 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/devicetypes/sinope-technologies/th1400zb-sinope-thermostat.src/th1400zb-sinope-thermostat.groovy b/devicetypes/sinope-technologies/th1400zb-sinope-thermostat.src/th1400zb-sinope-thermostat.groovy index 6ca78df95b8..bb8aeb3fddb 100644 --- a/devicetypes/sinope-technologies/th1400zb-sinope-thermostat.src/th1400zb-sinope-thermostat.groovy +++ b/devicetypes/sinope-technologies/th1400zb-sinope-thermostat.src/th1400zb-sinope-thermostat.groovy @@ -1,58 +1,65 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1.3.0 SVN-571 * 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. **/ metadata { - -preferences { - input("AirFloorModeParam", "enum", title: "Control mode (Default: Floor)", description:"Control mode using the floor or ambient temperature.", options: ["Ambient", "Floor"], multiple: false, required: false) - input("BacklightAutoDimParam", "enum", title:"Backlight setting (Default: Sensing)", description: "On Demand or Sensing", options: ["Sensing", "On Demand"], multiple: false, required: false) - input("KbdLockParam", "enum", title: "Keypad lock (Default: Unlocked)", description: "Enable or disable the device's buttons.",options: ["Lock", "Unlock"], multiple: false, required: false) - input("TimeFormatParam", "enum", title:"Time Format (Default: 24h)", description: "Time format displayed by the device.", options:["24h", "12h AM/PM"], multiple: false, required: false) - input("DisableOutdorTemperatureParam", "bool", title: "enable/disable outdoor temperature", description: "Set it to true to Disable outdoor temperature on the thermostat") - input("FloorSensorTypeParam", "enum", title:"Probe type (Default: 10k)", description: "Choose probe type.", options: ["10k", "12k"], multiple: false, required: false) - input("FloorMaxAirTemperatureParam", "number", title:"Ambient limit (5C to 36C / 41F to 96", range:("5..96"), - description: "The maximum ambient temperature limit when in floor control mode.", required: false) - input("FloorLimitMinParam", "number", title:"Floor low limit (5C to 36C / 41F to 96F)", range:("5..96"), description: "The minimum temperature limit of the floor when in ambient control mode.", required: false) - input("FloorLimitMaxParam", "number", title:"Floor high limit (5C to 36C / 41F to 96F)", range:("5..96"), description: "The maximum temperature limit of the floor when in ambient control mode.", required: false) - input("AuxLoadParam", "number", title:"Auxiliary load value (Default: 0)", range:("0..65535"), - description: "Enter the power in watts of the heating element connected to the auxiliary output.", required: false) - input("AuxiliaryCycleLengthParam", "enum", title:"Auxiliary cycle ltngth", options: ["disable, 15 seconds", "30 minutes"], required: false) - input("trace", "bool", title: "Trace (Only for debugging)", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") -} - - + preferences { + input("AirFloorModeParam", "enum", title: "Control mode (Default: Ambient)", + description:"Control mode using the floor or ambient temperature.", options: ["Ambient", "Floor"], multiple: false, required: false) + input("BacklightAutoDimParam", "enum", title:"Backlight setting (Default: Always ON)", + description: "On Demand or Always ON", options: ["On Demand", "Always ON"], multiple: false, required: false) + input("KbdLockParam", "enum", title: "Keypad lock (Default: Unlocked)", + description: "Enable or disable the device's buttons.",options: ["Lock", "Unlock"], multiple: false, required: false) + input("TimeFormatParam", "enum", title:"Time Format (Default: 24h)", + description: "Time \nformat \ndisplayed \nby the device.", options:["12h AM/PM", "24h"], multiple: false, required: false) + input("DisableOutdorTemperatureParam", "enum", title: "Secondary display (Default: Outside temp.)", multiple: false, required: false, options: ["Setpoint", "Outside temp."], + description: "Information displayed in the \nsecondary zone of the device") + input("FloorSensorTypeParam", "enum", title:"Probe type (Default: 10k)", + description: "Choose floor sensors probe. The floor sensor provided with the thermostats are 10K.", options: ["10k", "12k"], multiple: false, required: false) + + input("AuxiliaryCycleLengthParam", "enum", title:"Auxiliary cycle length", options: ["disable, 15 seconds", "30 minutes"], required: false) + + // input("PumpProtectionParam", "enum", titile: "Pump Protection (Default: Off)", options: ["On", "Off"], required: false + // description: "Activate the main output 1 minute every 24 hours to ensure the hydronics system pump does not seize.") + + input("FloorMaxAirTemperatureParam", "number", title:"Ambient limit in Celsius (5C to 36C)", range: "5..36", + description: "The maximum ambient temperature limit in Celsius when in floor control mode.", required: false) + input("FloorLimitMinParam", "number", title:"Floor low limit in Celsius (5C to 34C)", range: "5..34", + description: "The minimum temperature limit in Celsius of the floor when in ambient control mode.", required: false) + input("FloorLimitMaxParam", "number", title:"Floor high limit in Celsius (7C to 36C)", range: "7..36", + description: "The maximum temperature limit of the floor in Celsius when in ambient control mode.", required: false) + // input("AuxLoadParam", "number", title:"Auxiliary load value (Default: 0)", range:("0..65535"), + // description: "Enter the power in watts of the heating element connected to the auxiliary output.", required: false) + input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + } definition(name: "TH1400ZB Sinope Thermostat", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.thermostat") { - capability "thermostatHeatingSetpoint" - capability "thermostatMode" - capability "thermostatOperatingState" - capability "thermostatSetpoint" - capability "Actuator" capability "Temperature Measurement" + capability "Thermostat" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Actuator" capability "Configuration" + capability "Health check" capability "Refresh" capability "Sensor" - capability "lock" - attribute "temperatureDisplayMode", "enum", ["Deg_C", "Deg_F"] - attribute "occupancyStatus", "enum", ["unoccupy", "occupy"] attribute "outdoorTemp", "string" attribute "heatingSetpointRange", "VECTOR3" - attribute "verboseTrace", "string" attribute "floorLimitStatus", "enum", ["OK", "floorLimitLowReached", "floorLimitMaxReached", "floorAirLimitLowReached", "floorAirLimitMaxReached"] command "heatLevelUp" command "heatLevelDown" - fingerprint manufacturer: "Sinope Technologies", model: "TH1400ZB", deviceJoinName: "Sinope TH1400ZB Thermostat" + fingerprint manufacturer: "Sinope Technologies", model: "TH1400ZB", deviceJoinName: "Sinope Thermostat", mnmn: "SmartThings", vid: "SmartThings-smartthings-TH1300ZB_Sinope_Thermostat" //Sinope TH1400ZB Thermostat } + simulator { } //-------------------------------------------------------------------------------------------------------- tiles(scale: 2) { @@ -65,16 +72,12 @@ preferences { attributeState("VALUE_DOWN", action: "heatLevelDown") } tileAttribute("device.heatingDemand", key: "SECONDARY_CONTROL") { - attributeState("default", label: '${currentValue}%', unit: "%") + attributeState("default", label: '${currentValue}%', unit: "%", icon:"st.Weather.weather2") } tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { attributeState("idle", backgroundColor: "#44b621") attributeState("heating", backgroundColor: "#ffa81e") } - tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { - attributeState("off", label: '${name}') - attributeState("heat", label: '${name}') - } tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { attributeState("default", label: '${currentValue}', unit: "dF") } @@ -106,12 +109,7 @@ preferences { //-- Main & Details ---------------------------------------------------------------------------------------- main("thermostatMulti") - details(["thermostatMulti", - "heatingSetpointSlider", - "thermostatMode", - "floorLimitStatus", - "refresh" - ]) + details(["thermostatMulti", "heatingSetpointSlider", "thermostatMode", "floorLimitStatus", "refresh"]) } } @@ -145,6 +143,24 @@ def getBackgroundColors() { } +def getThermostatSetpointRange() { + (getTemperatureScale() == "C") ? [5, 36] : [41, 96] +} + +def getHeatingSetpointRange() { + thermostatSetpointRange +} + +def getSupportedThermostatModes() { + ["heat", "off"] +} + +def configureSupportedRanges() { + sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false) + // These are part of the deprecated Thermostat capability. Remove these when that capability is removed. + sendEvent(name: "thermostatSetpointRange", value: thermostatSetpointRange, displayed: false) + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, displayed: false) +} //-- Installation ---------------------------------------------------------------------------------------- @@ -156,8 +172,7 @@ def installed() { } def updated() { - - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 15000) { + if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 1000) { state.updatedLastRanAt = now() def cmds = [] @@ -168,27 +183,28 @@ def updated() { traceEvent(settings.logFilter, "updated>exception $e, continue processing", settings.trace, get_LOG_ERROR()) } + runIn(1,refresh_misc) runEvery15Minutes(refresh_misc) - if(AirFloorModeParam == "Ambient"){//Air mode + if(AirFloorModeParam == "Floor" || AirFloorModeParam == '1'){//Air mode traceEvent(settings.logFilter,"Set to Ambient mode",settings.trace) - cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0001) + cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0002) } else{//Floor mode traceEvent(settings.logFilter,"Set to Floor mode",settings.trace) - cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0002) + cmds += zigbee.writeAttribute(0xFF01, 0x0105, 0x30, 0x0001) } - if(KbdLockParam == "Lock"){ + if(KbdLockParam == "Lock" || KbdLockParam == '0'){ traceEvent(settings.logFilter,"device lock",settings.trace) - lock() + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) } else{ traceEvent(settings.logFilter,"device unlock",settings.trace) - unlock() + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) } - if(TimeFormatParam == "12h AM/PM"){//12h AM/PM + if(TimeFormatParam == "12h AM/PM" || TimeFormatParam == '0'){//12h AM/PM traceEvent(settings.logFilter,"Set to 12h AM/PM",settings.trace) cmds += zigbee.writeAttribute(0xFF01, 0x0114, 0x30, 0x0001) } @@ -197,7 +213,7 @@ def updated() { cmds += zigbee.writeAttribute(0xFF01, 0x0114, 0x30, 0x0000) } - if(BacklightAutoDimParam == "On Demand"){ //Backlight when needed + if(BacklightAutoDimParam == "On Demand" || BacklightAutoDimParam == '0'){ //Backlight when needed traceEvent(settings.logFilter,"Backlight on press",settings.trace) cmds += zigbee.writeAttribute(0x0201, 0x0402, 0x30, 0x0000) } @@ -206,7 +222,7 @@ def updated() { cmds += zigbee.writeAttribute(0x0201, 0x0402, 0x30, 0x0001) } - if(FloorSensorTypeParam == "12k"){//sensor type = 12k + if(FloorSensorTypeParam == "12k" || FloorSensorTypeParam == '1'){//sensor type = 12k traceEvent(settings.logFilter,"Sensor type is 12k",settings.trace) cmds += zigbee.writeAttribute(0xFF01, 0x010B, 0x30, 0x0001) } @@ -215,20 +231,30 @@ def updated() { cmds += zigbee.writeAttribute(0xFF01, 0x010B, 0x30, 0x0000) } + // if(PumpProtectionParam == "On" || FloorSensorTypeParam == '0'){//sensor type = 12k + // traceEvent(settings.logFilter,"Sensor type is 12k",settings.trace) + // cmds += zigbee.writeAttribute(0xFF01, 0x010B, 0x30, 0x0001) + // } + // else{//sensor type = 10k + // traceEvent(settings.logFilter,"Sensor type is 10k",settings.trace) + // cmds += zigbee.writeAttribute(0xFF01, 0x010B, 0x30, 0x0000) + // } + + state?.scale = getTemperatureScale() if(FloorMaxAirTemperatureParam){ def MaxAirTemperatureValue traceEvent(settings.logFilter,"FloorMaxAirTemperature param. scale: ${state?.scale}, Param value: ${FloorMaxAirTemperatureParam}",settings.trace) - if(state?.scale == 'F') + if(FloorMaxAirTemperatureParam >= 41) { - MaxAirTemperatureValue = fahrenheitToCelsius(FloorMaxAirTemperatureParam).toInteger() + MaxAirTemperatureValue = checkTemperature(FloorMaxAirTemperatureParam)//check if the temperature is between the maximum and minimum + MaxAirTemperatureValue = fahrenheitToCelsius(MaxAirTemperatureValue).toInteger() } else//state?.scale == 'C' { MaxAirTemperatureValue = FloorMaxAirTemperatureParam.toInteger() } - MaxAirTemperatureValue = checkTemperature(MaxAirTemperatureValue)//check if the temperature is between the maximum and minimum MaxAirTemperatureValue = MaxAirTemperatureValue * 100 cmds += zigbee.writeAttribute(0xFF01, 0x0108, 0x29, MaxAirTemperatureValue) } @@ -240,15 +266,15 @@ def updated() { if(FloorLimitMinParam){ def FloorLimitMinValue traceEvent(settings.logFilter,"FloorLimitMin param. scale: ${state?.scale}, Param value: ${FloorLimitMinParam}",settings.trace) - if(state?.scale == 'F') + if(FloorLimitMinParam >= 41) { - FloorLimitMinValue = fahrenheitToCelsius(FloorLimitMinParam).toInteger() + FloorLimitMinValue = checkTemperature(FloorLimitMinParam)//check if the temperature is between the maximum and minimum + FloorLimitMinValue = fahrenheitToCelsius(FloorLimitMinValue).toInteger() } else//state?.scale == 'C' { FloorLimitMinValue = FloorLimitMinParam.toInteger() } - FloorLimitMinValue = checkTemperature(FloorLimitMinValue)//check if the temperature is between the maximum and minimum FloorLimitMinValue = FloorLimitMinValue * 100 cmds += zigbee.writeAttribute(0xFF01, 0x0109, 0x29, FloorLimitMinValue) } @@ -260,15 +286,15 @@ def updated() { if(FloorLimitMaxParam){ def FloorLimitMaxValue traceEvent(settings.logFilter,"FloorLimitMax param. scale: ${state?.scale}, Param value: ${FloorLimitMaxParam}",settings.trace) - if(state?.scale == 'F') + if(FloorLimitMaxParam >= 45) { - FloorLimitMaxValue = fahrenheitToCelsius(FloorLimitMaxParam).toInteger() + FloorLimitMaxValue = checkTemperature(FloorLimitMaxParam)//check if the temperature is between the maximum and minimum + FloorLimitMaxValue = fahrenheitToCelsius(FloorLimitMaxValue).toInteger() } else//state?.scale == 'C' { FloorLimitMaxValue = FloorLimitMaxParam.toInteger() } - FloorLimitMaxValue = checkTemperature(FloorLimitMaxValue)//check if the temperature is between the maximum and minimum FloorLimitMaxValue = FloorLimitMaxValue * 100 cmds += zigbee.writeAttribute(0xFF01, 0x010A, 0x29, FloorLimitMaxValue) } @@ -288,12 +314,15 @@ def updated() { if(AuxiliaryCycleLengthParam){ switch (AuxiliaryCycleLengthParam) { + case "1": case "15 seconds": cmds += zigbee.writeAttribute(0x0201, 0x0404, 0x21, 0x000F)//15 sec break + case "2": case "30 minutes": cmds += zigbee.writeAttribute(0x0201, 0x0404, 0x21, 0x0708)//30min = 1800sec = 0x708 break + case "0": case "disable": default: cmds += zigbee.writeAttribute(0x0201, 0x0404, 0x21, 0x0000)//turn of the auxiliary @@ -313,35 +342,24 @@ def updated() { void initialize() { state?.scale = getTemperatureScale() - def supportedThermostatModes = ['off', 'heat'] state?.supportedThermostatModes = supportedThermostatModes - sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: (settings.trace ?: false)) + + configureSupportedRanges(); updated()//some thermostats values are not restored to a default value when disconnected. //executing the updated function make sure the thermostat parameters and the app parameters are in sync - if(state?.scale == 'C') - { - sendEvent(name: "heatingSetpointRange", value: [5.0, 36.0], scale: scale) - } - else if(state?.scale == 'F') - { - sendEvent(name: "heatingSetpointRangeLow", value: [41,96], scale: scale) - } - - sendEvent(name: "lock", value: "unlocked") - //for some reasons, the "runIn()" is not working in the "initialize()" of this driver. //to go around the problem, a read and a configuration is sent to each attribute required dor a good behaviour of the application def cmds = [] cmds += zigbee.readAttribute(0x0204, 0x0000) // Rd thermostat display mode if (state?.scale == 'C') { cmds += zigbee.writeAttribute(0x0204, 0x0000, 0x30, 0) // Wr °C on thermostat display - sendEvent(name: "heatingSetpointRange", value: [5,36], scale: state.scale) + sendEvent(name: "heatingSetpointRange", value: [5,36], scale: state?.scale) } else { cmds += zigbee.writeAttribute(0x0204, 0x0000, 0x30, 1) // Wr °F on thermostat display - sendEvent(name: "heatingSetpointRange", value: [41,96], scale: state.scale) + sendEvent(name: "heatingSetpointRange", value: [41,96], scale: state?.scale) } cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint @@ -362,12 +380,15 @@ void initialize() { def configure() { traceEvent(settings.logFilter, "Configuring Reporting and Bindings", settings.trace, get_LOG_DEBUG()) - //allow 30 min without receiving on/off report - return sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + //allow 5 min without receiving temperature report + return sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } def ping() { - refresh() + def cmds = []; + cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature + + sendZigbeeCommands(cmds) } def uninstalled() { @@ -405,10 +426,12 @@ def parse(String description) { def createCustomMap(descMap){ def result = null def map = [: ] - def scale = getTemperatureScale() + def scale = temperatureScale if (descMap.cluster == "0201" && descMap.attrId == "0000") { + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) map.name = "temperature" - map.value = getTemperatureValue(descMap.value, true) + map.value = getTemperatureValue(descMap.value, false) + map.unit = scale if(map.value > 158) {//if the value of the temperature is over 128C, it is considered an error with the temperature sensor map.value = "Sensor Error" @@ -426,13 +449,12 @@ def createCustomMap(descMap){ } } traceEvent(settings.logFilter, "parse>ACTUAL TEMP: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value, unit: scale) - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + //allow 5 min without receiving temperature report + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } else if (descMap.cluster == "0201" && descMap.attrId == "0008") { map.name = "heatingDemand" map.value = getHeatingDemand(descMap.value) - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}") def operatingState = (map.value.toInteger() < 10) ? "idle" : "heating" sendEvent(name: "thermostatOperatingState", value: operatingState) @@ -440,23 +462,18 @@ def createCustomMap(descMap){ } else if (descMap.cluster == "0201" && descMap.attrId == "0012") { + configureSupportedRanges(); + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) map.name = "heatingSetpoint" map.value = getTemperatureValue(descMap.value, true) - sendEvent(name: map.name, value: map.value, unit: scale) + map.unit = scale traceEvent(settings.logFilter, "parse>OCCUPY: ${map.name}: ${map.value}, scale: ${scale} ", settings.trace) } else if (descMap.cluster == "0201" && descMap.attrId == "001c") { map.name = "thermostatMode" map.value = getModeMap()[descMap.value] - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}", settings.trace) } - else if (descMap.cluster == "0204" && descMap.attrId == "0001") { - map.name = "keypadLockStatus" - map.value = getLockMap()[descMap.value] - traceEvent(settings.logFilter, "parse>KEYPAD LOCK STATUS: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value) - } else if (descMap.cluster == "FF01" && descMap.attrId == "010c") { map.name = "floorLimitStatus" if(descMap.value.toInteger() == 0){ @@ -470,10 +487,14 @@ def createCustomMap(descMap){ }else{ map.value = "floorAirLimitMaxReached" } + if(map.value != "OK"){ + log.warn map.value + } traceEvent(settings.logFilter, "parse>floorLimitStatus: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value) } - + if(map){ + result = createEvent(map); + } return result } @@ -556,7 +577,7 @@ def heatLevelDown() { } def setHeatingSetpoint(degrees) { - def scale = state?.scale + def scale = getTemperatureScale() degrees = checkTemperature(degrees) def degreesDouble = degrees as Double String tempValueString @@ -565,8 +586,6 @@ def setHeatingSetpoint(degrees) { } else { tempValueString = String.format('%2d', degreesDouble.intValue()) } - sendEvent("name": "heatingSetpoint", "value": tempValueString, scale: scale) - sendEvent("name": "thermostatSetpoint", "value": tempValueString, scale: scale) traceEvent(settings.logFilter, "setHeatingSetpoint> new setPoint: $tempValueString", settings.trace) def celsius = (scale == "C") ? degreesDouble : (fahrenheitToCelsius(degreesDouble) as Double).round(1) def cmds = [] @@ -603,19 +622,9 @@ def getModeMap() { ] } -def getSupportedThermostatModes() { - - if (!state?.supportedThermostatModes) { - state?.supportedThermostatModes = (device.currentValue("supportedThermostatModes")) ? - device.currentValue("supportedThermostatModes").toString().minus('[').minus(']').tokenize(',') : ['off', 'heat'] - } - return state?.supportedThermostatModes -} - def setThermostatMode(mode) { traceEvent(settings.logFilter, "setThermostatMode>switching thermostatMode", settings.trace) mode = mode?.toLowerCase() - def supportedThermostatModes = getSupportedThermostatModes() if (mode in supportedThermostatModes) { "mode_$mode" () @@ -626,22 +635,20 @@ def setThermostatMode(mode) { def mode_off() { traceEvent(settings.logFilter, "off>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "off", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 0) - cmds += zigbee.readAttribute(0x0201, 0x0008) - sendZigbeeCommands(cmds) + cmds += zigbee.readAttribute(0x0201, 0x001C) traceEvent(settings.logFilter, "off>end", settings.trace) + sendZigbeeCommands(cmds) } def mode_heat() { traceEvent(settings.logFilter, "heat>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "heat", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 4) - cmds += zigbee.readAttribute(0x0201, 0x0008) - sendZigbeeCommands(cmds) + cmds += zigbee.readAttribute(0x0201, 0x001C) traceEvent(settings.logFilter, "heat>end", settings.trace) + sendZigbeeCommands(cmds) } //-- Keypad Lock ----------------------------------------------------------------------------------------- @@ -656,51 +663,14 @@ def getLockMap() { ] } -def unlock() { - traceEvent(settings.logFilter, "unlock>begin", settings.trace) - sendEvent(name: "lock", value: "unlocked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) - sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "unlock>end", settings.trace) -} - -def lock() { - traceEvent(settings.logFilter, "lock>begin", settings.trace) - sendEvent(name: "lock", value: "locked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) - sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "lock>end", settings.trace) -} - def refresh() { - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 20000) { // Check if last update > 20 sec + if (true || !state.updatedLastRanAt || now() >= state.updatedLastRanAt + 5000) { // Check if last update > 5 sec state.updatedLastRanAt = now() state?.scale = getTemperatureScale() traceEvent(settings.logFilter, "refresh>scale=${state.scale}", settings.trace) def cmds = [] - cmds += zigbee.readAttribute(0x0204, 0x0000) // Rd thermostat display mode - - def heatingSetpointRangeHigh - def heatingSetpointRangeLow - if(state?.scale == 'C') - { - heatingSetpointRangeLow = 5.0 - heatingSetpointRangeHigh = 36.0 - } - else if(state?.scale == 'F') - { - heatingSetpointRangeLow = 41 - heatingSetpointRangeHigh = 96 - } - def low = heatingSetpointRangeLow.toFloat().round(1) - def high = heatingSetpointRangeHigh.toFloat().round(1) - def heatingSetpointRange= [low,high] - sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) - cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint cmds += zigbee.readAttribute(0x0201, 0x0008) // Rd thermostat PI heating demand @@ -710,11 +680,6 @@ def refresh() { cmds += zigbee.readAttribute(0x0201, 0x0016) // Rd thermostat Maximum heating setpoint cmds += zigbee.readAttribute(0xFF01, 0x0105) // Rd thermostat Control mode - cmds += zigbee.configureReporting(0x0201, 0x0000, 0x29, 19, 300, 25) // local temperature - cmds += zigbee.configureReporting(0x0201, 0x0008, 0x0020, 11, 301, 10) // heating demand - cmds += zigbee.configureReporting(0x0201, 0x0012, 0x0029, 8, 302, 40) // occupied heating setpoint - cmds += zigbee.configureReporting(0xFF01, 0x010C, 0x30, 10, 3600, 1) // floor limit status each hours - sendZigbeeCommands(cmds) refresh_misc() } @@ -737,8 +702,11 @@ void refresh_misc() { int outdoorTempValue int outdoorTempToSend - if(!settings.DisableOutdorTemperatureParam) - { + if(DisableOutdorTemperatureParam == "Setpoint" || DisableOutdorTemperatureParam == "0") + {//delete outdoorTemp + cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, 0x8000) + } + else{ cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 10800)//set the outdoor temperature timeout to 3 hours if (outdoorTemp < 0) { outdoorTempValue = -outdoorTemp*100 - 65536 @@ -753,12 +721,6 @@ void refresh_misc() { cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, outdoorTempToSend, [mfgCode: 0x119C]) } } - else - {//delete outdoorTemp - //the outdoor temperature cannot be directly erased from the thermostat. - //to erase it rapidly, the external temperature timeout must be set to the minimal value (30sec) - cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 30)//set the outdoor temperature timeout to 30sec - } def mytimezone = location.getTimeZone() long dstSavings = 0 @@ -788,7 +750,7 @@ void refresh_misc() { //-- Private functions ----------------------------------------------------------------------------------- -void sendZigbeeCommands(cmds, delay = 1000) { +void sendZigbeeCommands(cmds, delay = 250) { cmds.removeAll { it.startsWith("delay") } // convert each command into a HubAction cmds = cmds.collect { new physicalgraph.device.HubAction(it) } @@ -882,35 +844,25 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } } \ No newline at end of file diff --git a/devicetypes/sinope-technologies/th1500zb-sinope-thermostat.src/th1500zb-sinope-thermostat.groovy b/devicetypes/sinope-technologies/th1500zb-sinope-thermostat.src/th1500zb-sinope-thermostat.groovy index bae153df063..158c3836207 100644 --- a/devicetypes/sinope-technologies/th1500zb-sinope-thermostat.src/th1500zb-sinope-thermostat.groovy +++ b/devicetypes/sinope-technologies/th1500zb-sinope-thermostat.src/th1500zb-sinope-thermostat.groovy @@ -1,7 +1,6 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1.3.0 SVN-571 * 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. @@ -10,38 +9,39 @@ SVN-571 metadata { preferences { - input("BacklightAutoDimParam", "enum", title:"Backlight setting (Default: Sensing)", description: "On Demand or Sensing", options: ["Sensing", "On Demand"], multiple: false, required: false) - input("KbdLockParam", "enum", title: "Keypad lock (Default: Unlocked)", description: "Enable or disable the device's buttons.",options: ["Lock", "Unlock"], multiple: false, required: false) - input("TimeFormatParam", "enum", title:"Time Format (Default: 24h)", description: "Time format displayed by the device.", options:["24h", "12h AM/PM"], multiple: false, required: false) - input("DisableOutdorTemperatureParam", "bool", title: "enable/disable outdoor temperature", description: "Set it to true to Disable outdoor temperature on the thermostat") + input("BacklightAutoDimParam", "enum", title:"Backlight setting (Default: Always ON)", + description: "On Demand or Always ON", options: ["On Demand", "Always ON"], multiple: false, required: false) + input("KbdLockParam", "enum", title: "Keypad lock (Default: Unlocked)", + description: "Enable or disable the device's buttons.",options: ["Lock", "Unlock"], multiple: false, required: false) + input("TimeFormatParam", "enum", title:"Time Format (Default: 24h)", + description: "Time format displayed by the device.", options:["12h AM/PM", "24h"], multiple: false, required: false) + input("DisableOutdorTemperatureParam", "enum", title: "Secondary display (Default: Outside temp.)", multiple: false, required: false, options: ["Setpoint", "Outside temp."], + description: "Information displayed in the secondary zone of the device") input("trace", "bool", title: "Trace (Only for debugging)", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") } definition(name: "TH1500ZB Sinope Thermostat", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.thermostat") { - capability "thermostatHeatingSetpoint" - capability "thermostatMode" - capability "thermostatOperatingState" - capability "thermostatSetpoint" - capability "Actuator" capability "Temperature Measurement" + capability "Thermostat" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Actuator" capability "Configuration" + capability "Health check" capability "Refresh" capability "Sensor" - capability "lock" - attribute "temperatureDisplayMode", "enum", ["Deg_C", "Deg_F"] - attribute "occupancyStatus", "enum", ["unoccupy", "occupy"] attribute "outdoorTemp", "string" attribute "heatingSetpointRange", "VECTOR3" - attribute "verboseTrace", "string" command "heatLevelUp" command "heatLevelDown" - fingerprint manufacturer: "Sinope Technologies", model: "TH1500ZB", deviceJoinName: "Sinope TH1500ZB Thermostat" + fingerprint manufacturer: "Sinope Technologies", model: "TH1500ZB", deviceJoinName: "Sinope Thermostat", mnmn: "SmartThings", vid: "SmartThings-smartthings-TH1300ZB_Sinope_Thermostat" //Sinope TH1500ZB Thermostat } //-------------------------------------------------------------------------------------------------------- @@ -55,7 +55,7 @@ preferences { attributeState("VALUE_DOWN", action: "heatLevelDown") } tileAttribute("device.heatingDemand", key: "SECONDARY_CONTROL") { - attributeState("default", label: '${currentValue}%', unit: "%") + attributeState("default", label: '${currentValue}%', unit: "%", icon:"st.Weather.weather2") } tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { attributeState("idle", backgroundColor: "#44b621") @@ -88,44 +88,28 @@ preferences { //-- Main & Details ---------------------------------------------------------------------------------------- main("thermostatMulti") - details(["thermostatMulti", - "heatingSetpointSlider", - "thermostatMode", - "refresh" - ]) + details(["thermostatMulti", "heatingSetpointSlider", "thermostatMode", "refresh"]) } } -def getBackgroundColors() { - def results - if (state?.scale == 'C') { - // Celsius Color Range - results = [ - [value: 0, color: "#153591"], - [value: 7, color: "#1e9cbb"], - [value: 15, color: "#90d2a7"], - [value: 23, color: "#44b621"], - [value: 29, color: "#f1d801"], - [value: 35, color: "#d04e00"], - [value: 37, color: "#bc2323"] - ] - } else { - results = - // Fahrenheit Color Range - [ - [value: 31, color: "#153591"], - [value: 44, color: "#1e9cbb"], - [value: 59, color: "#90d2a7"], - [value: 74, color: "#44b621"], - [value: 84, color: "#f1d801"], - [value: 95, color: "#d04e00"], - [value: 96, color: "#bc2323"] - ] - } - return results - +def getThermostatSetpointRange() { + (getTemperatureScale() == "C") ? [5, 36] : [41, 96] +} + +def getHeatingSetpointRange() { + thermostatSetpointRange } +def getSupportedThermostatModes() { + ["heat", "off"] +} + +def configureSupportedRanges() { + sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false) + // These are part of the deprecated Thermostat capability. Remove these when that capability is removed. + sendEvent(name: "thermostatSetpointRange", value: thermostatSetpointRange, displayed: false) + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, displayed: false) +} //-- Installation ---------------------------------------------------------------------------------------- @@ -138,7 +122,7 @@ def installed() { def updated() { - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 15000) { + if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 1000) { state.updatedLastRanAt = now() def cmds = [] @@ -151,16 +135,16 @@ def updated() { runEvery15Minutes(refresh_misc) - if(KbdLockParam == "Lock"){ + if(KbdLockParam == "Lock" || KbdLockParam == '0'){ traceEvent(settings.logFilter,"device lock",settings.trace) - lock() + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) } else{ traceEvent(settings.logFilter,"device unlock",settings.trace) - unlock() + cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) } - if(TimeFormatParam == "12h AM/PM"){//12h AM/PM + if(TimeFormatParam == "12h AM/PM" || TimeFormatParam == '0'){//12h AM/PM traceEvent(settings.logFilter,"Set to 12h AM/PM",settings.trace) cmds += zigbee.writeAttribute(0xFF01, 0x0114, 0x30, 0x0001) } @@ -187,23 +171,13 @@ def updated() { void initialize() { state?.scale = getTemperatureScale() - def supportedThermostatModes = ['off', 'heat'] state?.supportedThermostatModes = supportedThermostatModes - sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: (settings.trace ?: false)) + + configureSupportedRanges(); updated()//some thermostats values are not restored to a default value when disconnected. //executing the updated function make sure the thermostat parameters and the app parameters are in sync - if(state?.scale == 'C') - { - sendEvent(name: "heatingSetpointRange", value: [5.0, 36.0], scale: scale) - } - else if(state?.scale == 'F') - { - sendEvent(name: "heatingSetpointRangeLow", value: [41,96], scale: scale) - } - - sendEvent(name: "lock", value: "unlocked") //for some reasons, the "runIn()" is not working in the "initialize()" of this driver. //to go around the problem, a read and a configuration is sent to each attribute required dor a good behaviour of the application @@ -221,7 +195,6 @@ void initialize() { cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint cmds += zigbee.readAttribute(0x0201, 0x0008) // Rd thermostat PI heating demand cmds += zigbee.readAttribute(0x0201, 0x001C) // Rd thermostat System Mode - cmds += zigbee.readAttribute(0x0204, 0x0001) // Rd thermostat Keypad lockout cmds += zigbee.readAttribute(0xFF01, 0x0105) // Rd thermostat Control mode cmds += zigbee.configureReporting(0x0201, 0x0000, 0x29, 19, 300, 25) // local temperature @@ -240,7 +213,9 @@ def configure() } def ping() { - refresh() + def cmds = []; + cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature + sendZigbeeCommands(cmds) } def uninstalled() { @@ -278,10 +253,12 @@ def parse(String description) { def createCustomMap(descMap){ def result = null def map = [: ] - def scale = getTemperatureScale() + def scale = temperatureScale if (descMap.cluster == "0201" && descMap.attrId == "0000") { + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) map.name = "temperature" - map.value = getTemperatureValue(descMap.value, true) + map.value = getTemperatureValue(descMap.value, false) + map.unit = scale if(map.value > 158) {//if the value of the temperature is over 128C, it is considered an error with the temperature sensor map.value = "Sensor Error" @@ -297,16 +274,14 @@ def createCustomMap(descMap){ { map.value = String.format( "%d", map.value ) } - } traceEvent(settings.logFilter, "parse>ACTUAL TEMP: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value, unit: scale) - sendEvent(name: "checkInterval", value: 30*60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + //allow 5 min without receiving temperature report + sendEvent(name: "checkInterval", value: 300, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) } else if (descMap.cluster == "0201" && descMap.attrId == "0008") { map.name = "heatingDemand" map.value = getHeatingDemand(descMap.value) - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}") def operatingState = (map.value.toInteger() < 10) ? "idle" : "heating" sendEvent(name: "thermostatOperatingState", value: operatingState) @@ -314,23 +289,21 @@ def createCustomMap(descMap){ } else if (descMap.cluster == "0201" && descMap.attrId == "0012") { + configureSupportedRanges(); + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) map.name = "heatingSetpoint" map.value = getTemperatureValue(descMap.value, true) - sendEvent(name: map.name, value: map.value, unit: scale) + map.unit = scale traceEvent(settings.logFilter, "parse>OCCUPY: ${map.name}: ${map.value}, scale: ${scale} ", settings.trace) } else if (descMap.cluster == "0201" && descMap.attrId == "001c") { map.name = "thermostatMode" map.value = getModeMap()[descMap.value] - sendEvent(name: map.name, value: map.value) traceEvent(settings.logFilter, "parse>${map.name}: ${map.value}", settings.trace) } - else if (descMap.cluster == "0204" && descMap.attrId == "0001") { - map.name = "keypadLockStatus" - map.value = getLockMap()[descMap.value] - traceEvent(settings.logFilter, "parse>KEYPAD LOCK STATUS: ${map.value}", settings.trace) - sendEvent(name: map.name, value: map.value) - } + if(map){ + result = createEvent(map); + } return result } @@ -427,8 +400,6 @@ def setHeatingSetpoint(degrees) { } else { tempValueString = String.format('%2d', degreesDouble.intValue()) } - sendEvent("name": "heatingSetpoint", "value": tempValueString, scale: scale) - sendEvent("name": "thermostatSetpoint", "value": tempValueString, scale: scale) traceEvent(settings.logFilter, "setHeatingSetpoint> new setPoint: $tempValueString", settings.trace) def celsius = (scale == "C") ? degreesDouble : (fahrenheitToCelsius(degreesDouble) as Double).round(1) def cmds = [] @@ -465,19 +436,9 @@ def getModeMap() { ] } -def getSupportedThermostatModes() { - - if (!state?.supportedThermostatModes) { - state?.supportedThermostatModes = (device.currentValue("supportedThermostatModes")) ? - device.currentValue("supportedThermostatModes").toString().minus('[').minus(']').tokenize(',') : ['off', 'heat'] - } - return state?.supportedThermostatModes -} - def setThermostatMode(mode) { traceEvent(settings.logFilter, "setThermostatMode>switching thermostatMode", settings.trace) mode = mode?.toLowerCase() - def supportedThermostatModes = getSupportedThermostatModes() if (mode in supportedThermostatModes) { "mode_$mode" () @@ -488,94 +449,38 @@ def setThermostatMode(mode) { def mode_off() { traceEvent(settings.logFilter, "off>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "off", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 0) - cmds += zigbee.readAttribute(0x0201, 0x0008) - sendZigbeeCommands(cmds) + cmds += zigbee.readAttribute(0x0201, 0x001C) traceEvent(settings.logFilter, "off>end", settings.trace) + sendZigbeeCommands(cmds) } def mode_heat() { traceEvent(settings.logFilter, "heat>begin", settings.trace) - sendEvent(name: "thermostatMode", value: "heat", data: [supportedThermostatModes: getSupportedThermostatModes()]) def cmds = [] cmds += zigbee.writeAttribute(0x0201, 0x001C, 0x30, 4) - cmds += zigbee.readAttribute(0x0201, 0x0008) - sendZigbeeCommands(cmds) + cmds += zigbee.readAttribute(0x0201, 0x001C) traceEvent(settings.logFilter, "heat>end", settings.trace) -} -//-- Keypad Lock ----------------------------------------------------------------------------------------- - -def keypadLockLevel() { - ["unlock", "lock"] //only those level are used for the moment -} - -def getLockMap() { - [ - "00": "unlocked", - "01": "locked", - ] -} - -def unlock() { - traceEvent(settings.logFilter, "unlock>begin", settings.trace) - sendEvent(name: "lock", value: "unlocked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x00) sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "unlock>end", settings.trace) -} - -def lock() { - traceEvent(settings.logFilter, "lock>begin", settings.trace) - sendEvent(name: "lock", value: "locked") - def cmds = [] - cmds += zigbee.writeAttribute(0x0204, 0x0001, 0x30, 0x01) - sendZigbeeCommands(cmds) - traceEvent(settings.logFilter, "lock>end", settings.trace) } def refresh() { - if (!state.updatedLastRanAt || now() >= state.updatedLastRanAt + 20000) { // Check if last update > 20 sec + if (true || !state.updatedLastRanAt || now() >= state.updatedLastRanAt + 5000) { // Check if last update > 5 sec state.updatedLastRanAt = now() state?.scale = getTemperatureScale() traceEvent(settings.logFilter, "refresh>scale=${state.scale}", settings.trace) def cmds = [] - cmds += zigbee.readAttribute(0x0204, 0x0000) // Rd thermostat display mode - - def heatingSetpointRangeHigh - def heatingSetpointRangeLow - if(state?.scale == 'C') - { - heatingSetpointRangeLow = 5.0 - heatingSetpointRangeHigh = 36.0 - } - else if(state?.scale == 'F') - { - heatingSetpointRangeLow = 41 - heatingSetpointRangeHigh = 96 - } - def low = heatingSetpointRangeLow.toFloat().round(1) - def high = heatingSetpointRangeHigh.toFloat().round(1) - def heatingSetpointRange= [low,high] - sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, scale: state.scale) - cmds += zigbee.readAttribute(0x0201, 0x0000) // Rd thermostat Local temperature cmds += zigbee.readAttribute(0x0201, 0x0012) // Rd thermostat Occupied heating setpoint cmds += zigbee.readAttribute(0x0201, 0x0008) // Rd thermostat PI heating demand cmds += zigbee.readAttribute(0x0201, 0x001C) // Rd thermostat System Mode - cmds += zigbee.readAttribute(0x0204, 0x0001) // Rd thermostat Keypad lockout cmds += zigbee.readAttribute(0x0201, 0x0015) // Rd thermostat Minimum heating setpoint cmds += zigbee.readAttribute(0x0201, 0x0016) // Rd thermostat Maximum heating setpoint cmds += zigbee.readAttribute(0xFF01, 0x0105) // Rd thermostat Control mode - cmds += zigbee.configureReporting(0x0201, 0x0000, 0x29, 19, 300, 25) // local temperature - cmds += zigbee.configureReporting(0x0201, 0x0008, 0x0020, 11, 301, 10) // heating demand - cmds += zigbee.configureReporting(0x0201, 0x0012, 0x0029, 8, 302, 40) // occupied heating setpoint - sendZigbeeCommands(cmds) refresh_misc() } @@ -598,8 +503,10 @@ void refresh_misc() { int outdoorTempValue int outdoorTempToSend - if(!settings.DisableOutdorTemperatureParam) - { + if(DisableOutdorTemperatureParam == "Setpoint" || DisableOutdorTemperatureParam == "0"){//delete outdoorTemp + cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, 0x8000) + } + else{ cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 10800)//set the outdoor temperature timeout to 3 hours if (outdoorTemp < 0) { outdoorTempValue = -outdoorTemp*100 - 65536 @@ -614,12 +521,6 @@ void refresh_misc() { cmds += zigbee.writeAttribute(0xFF01, 0x0010, 0x29, outdoorTempToSend, [mfgCode: 0x119C]) } } - else - {//delete outdoorTemp - //the outdoor temperature cannot be directly erased from the thermostat. - //to erase it rapidly, the external temperature timeout must be set to the minimal value (30sec) - cmds += zigbee.writeAttribute(0xFF01, 0x0011, 0x21, 30)//set the outdoor temperature timeout to 30sec - } def mytimezone = location.getTimeZone() long dstSavings = 0 @@ -649,7 +550,7 @@ void refresh_misc() { //-- Private functions ----------------------------------------------------------------------------------- -void sendZigbeeCommands(cmds, delay = 1000) { +void sendZigbeeCommands(cmds, delay = 250) { cmds.removeAll { it.startsWith("delay") } // convert each command into a HubAction cmds = cmds.collect { new physicalgraph.device.HubAction(it) } @@ -743,35 +644,25 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } } \ No newline at end of file diff --git a/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy b/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy index 29940f46ba2..da0602ea1cd 100644 --- a/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy +++ b/devicetypes/sinope-technologies/va4200wz-va4200zb-sinope-valve.src/va4200wz-va4200zb-sinope-valve.groovy @@ -1,7 +1,6 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1..0 SVN-571 * 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. @@ -13,8 +12,8 @@ metadata { preferences { input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") } definition (name: "VA4200WZ-VA4200ZB Sinope Valve", namespace: "Sinope Technologies", author: "Sinope Technologies", ocfDeviceType: "oic.d.watervalve") { @@ -26,8 +25,8 @@ metadata { capability "Power Source" capability "Health Check" - fingerprint manufacturer: "Sinope Technologies", model: "VA4200WZ", deviceJoinName: "VA4200WZ" - fingerprint manufacturer: "Sinope Technologies", model: "VA4200ZB", deviceJoinName: "VA4200ZB" + fingerprint manufacturer: "Sinope Technologies", model: "VA4200WZ", deviceJoinName: "Sinope Valve" //VA4200WZ + fingerprint manufacturer: "Sinope Technologies", model: "VA4200ZB", deviceJoinName: "Sinope Valve" //VA4200ZB } tiles(scale: 2) { @@ -292,35 +291,25 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } } \ No newline at end of file diff --git a/devicetypes/sinope-technologies/wl4200s-wl4200-sinope-water-leak-sensor.src/wl4200s-wl4200-sinope-water-leak-sensor.groovy b/devicetypes/sinope-technologies/wl4200s-wl4200-sinope-water-leak-sensor.src/wl4200s-wl4200-sinope-water-leak-sensor.groovy index 7e73234abe3..1cd25862e10 100644 --- a/devicetypes/sinope-technologies/wl4200s-wl4200-sinope-water-leak-sensor.src/wl4200s-wl4200-sinope-water-leak-sensor.groovy +++ b/devicetypes/sinope-technologies/wl4200s-wl4200-sinope-water-leak-sensor.src/wl4200s-wl4200-sinope-water-leak-sensor.groovy @@ -1,7 +1,6 @@ /** - -Copyright Sinopé Technologies 2019 -1.1.0 +Copyright Sinopé Technologies +1.3.0 SVN-571 * 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. @@ -12,8 +11,8 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus preferences { section { input("trace", "bool", title: "Trace", description: "Set it to true to enable tracing") - input("logFilter", "number", title: "Trace level", range: "1..5", - description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") + // input("logFilter", "number", title: "Trace level", range: "1..5", + // description: "1= ERROR only, 2= <1+WARNING>, 3= <2+INFO>, 4= <3+DEBUG>, 5= <4+TRACE>") } } @@ -29,8 +28,8 @@ metadata { attribute "sensor", "enum", ["disconnected", "connected"] //this attribute is used by the "sensor" tile - fingerprint manufacturer: "Sinope Technologies", model: "WL4200", deviceJoinName: "WL4200" - fingerprint manufacturer: "Sinope Technologies", model: "WL4200S", deviceJoinName: "WL4200S" + fingerprint manufacturer: "Sinope Technologies", model: "WL4200", deviceJoinName: "Sinope Water Leak Sensor" //WL4200 + fingerprint manufacturer: "Sinope Technologies", model: "WL4200S", deviceJoinName: "Sinope Water Leak Sensor" //WL4200S } tiles(scale: 2) { @@ -320,36 +319,26 @@ def traceEvent(logFilter, message, displayEvent = false, traceLevel = 4, sendMes int LOG_INFO = get_LOG_INFO() int LOG_DEBUG = get_LOG_DEBUG() int LOG_TRACE = get_LOG_TRACE() - int filterLevel = (logFilter) ? logFilter.toInteger() : get_LOG_WARN() - - if ((displayEvent) || (sendMessage)) { - def results = [ - name: "verboseTrace", - value: message, - displayed: ((displayEvent) ?: false) - ] - - if ((displayEvent) && (filterLevel >= traceLevel)) { - switch (traceLevel) { - case LOG_ERROR: - log.error "${message}" - break - case LOG_WARN: - log.warn "${message}" - break - case LOG_INFO: - log.info "${message}" - break - case LOG_TRACE: - log.trace "${message}" - break - case LOG_DEBUG: - default: - log.debug "${message}" - break - } /* end switch*/ - if (sendMessage) sendEvent(results) - } /* end if displayEvent*/ + + if (displayEvent || traceLevel < 4) { + switch (traceLevel) { + case LOG_ERROR: + log.error "${message}" + break + case LOG_WARN: + log.warn "${message}" + break + case LOG_INFO: + log.info "${message}" + break + case LOG_TRACE: + log.trace "${message}" + break + case LOG_DEBUG: + default: + log.debug "${message}" + break + } } } diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy old mode 100644 new mode 100755 index fb906937c1a..68b6e77aa96 --- a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/Orvibo-Contact-Sensor.groovy @@ -28,9 +28,11 @@ metadata { capability "Refresh" capability "Health Check" capability "Sensor" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500", outClusters: "0003", manufacturer: "eWeLink", model: "DS01", deviceJoinName: "eWeLink Door Sensor" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer: "ORVIBO", model: "e70f96b3773a4c9283c6862dbafb6a99" - fingerprint inClusters: "0000,0001,0003,000F,0020,0500", outClusters: "000A,0019", manufacturer: "Aurora", model: "WindowSensor51AU", deviceJoinName: "Aurora Smart Door/Window Sensor" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500", outClusters: "0003", manufacturer: "eWeLink", model: "DS01", deviceJoinName: "eWeLink Open/Closed Sensor" //eWeLink Door Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer: "ORVIBO", model: "e70f96b3773a4c9283c6862dbafb6a99", deviceJoinName: "Orvibo Open/Closed Sensor" + fingerprint inClusters: "0000,0001,0003,000F,0020,0500", outClusters: "000A,0019", manufacturer: "Aurora", model: "WindowSensor51AU", deviceJoinName: "Aurora Open/Closed Sensor" //Aurora Smart Door/Window Sensor + fingerprint manufacturer: "Aurora", model: "DoorSensor50AU", deviceJoinName: "Aurora Open/Closed Sensor" // Raw Description: 01 0104 0402 00 06 0000 0001 0003 0020 0500 0B05 01 0019 //Aurora Smart Door/Window Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer: "HEIMAN", model: "DoorSensor-N", deviceJoinName: "HEIMAN Open/Closed Sensor" //HEIMAN Door Sensor } simulator { @@ -117,7 +119,7 @@ def refresh() { log.debug "Refreshing Battery and ZONE Status" def manufacturer = getDataValue("manufacturer") def refreshCmds = zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) - if (manufacturer == "ORVIBO" || manufacturer == "eWeLink") { + if (manufacturer == "ORVIBO" || manufacturer == "eWeLink" || manufacturer == "HEIMAN") { refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021) } else { // this is actually just supposed to be for Aurora, but we'll make it the default as it's more widely supported refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) @@ -139,7 +141,7 @@ def configure() { //The electricity attribute is reported without bind and reporting CFG. The TI plan reports the power once in about 10 minutes; the NXP plan reports the electricity once in 20 minutes if (manufacturer == "Aurora") { cmds = zigbee.enrollResponse() + zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, 30, 60 * 5, null) + zigbee.batteryConfig() - } else if (manufacturer == "eWeLink") { + } else if (manufacturer == "eWeLink" || manufacturer == "HEIMAN") { cmds = zigbee.enrollResponse() + zigbee.configureReporting(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS, DataType.BITMAP16, 30, 60 * 5, null) + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0021, DataType.UINT8, 30, 600, 1) } cmds += refresh() diff --git a/devicetypes/smartthings/Orvibo-Contact-Sensor.src/i18n/messages.properties b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/i18n/messages.properties new file mode 100755 index 00000000000..22aba42eeab --- /dev/null +++ b/devicetypes/smartthings/Orvibo-Contact-Sensor.src/i18n/messages.properties @@ -0,0 +1,17 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Open/Closed Sensor'''.zh-cn=海曼门窗传感器 +'''HEIMAN Door Sensor'''.zh-cn=海曼门窗传感器 diff --git a/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy b/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy index c4f2df261d7..9cd3d420225 100644 --- a/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy +++ b/devicetypes/smartthings/aeon-home-energy-meter.src/aeon-home-energy-meter.groovy @@ -27,10 +27,10 @@ metadata { command "reset" - fingerprint deviceId: "0x2101", inClusters: " 0x70,0x31,0x72,0x86,0x32,0x80,0x85,0x60" - fingerprint mfr: "0086", prod: "0102", model: "005F", deviceJoinName: "Home Energy Meter (Gen5)" // US - fingerprint mfr: "0086", prod: "0002", model: "005F", deviceJoinName: "Home Energy Meter (Gen5)" // EU - fingerprint mfr: "0159", prod: "0007", model: "0052", deviceJoinName: "Qubino Smart Meter" + fingerprint deviceId: "0x2101", inClusters: " 0x70,0x31,0x72,0x86,0x32,0x80,0x85,0x60", deviceJoinName: "Aeon Energy Monitor" + fingerprint mfr: "0086", prod: "0102", model: "005F", deviceJoinName: "Aeon Energy Monitor" // US //Home Energy Meter (Gen5) + fingerprint mfr: "0086", prod: "0002", model: "005F", deviceJoinName: "Aeon Energy Monitor" // EU //Home Energy Meter (Gen5) + fingerprint mfr: "0159", prod: "0007", model: "0052", deviceJoinName: "Qubino Energy Monitor" //Qubino Smart Meter } // simulator metadata @@ -139,6 +139,8 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { def refresh() { log.debug "refresh()..." delayBetween([ + encap(zwave.associationV2.associationRemove(groupingIdentifier: 1, nodeId:[])), // Refresh Node ID in Group 1 + encap(zwave.associationV2.associationSet(groupingIdentifier: 1, nodeId:zwaveHubNodeId)), //Assign Node ID of SmartThings to Group 1 encap(zwave.meterV2.meterGet(scale: 0)), encap(zwave.meterV2.meterGet(scale: 2)) ]) @@ -157,13 +159,12 @@ def configure() { log.debug "configure()..." if (isAeotecHomeEnergyMeter()) delayBetween([ - encap(zwave.configurationV1.configurationSet(parameterNumber: 255, size: 4, scaledConfigurationValue: 1)), // Reset the device to the default settings - encap(zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 1)), // report power in Watts... + encap(zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 3)), // report total power in Watts and total energy in kWh... + encap(zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 0)), // disable group 2... + encap(zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0)), // disable group 3... encap(zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 300)), // ...every 5 min - encap(zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 2)), // report energy in kWh... - encap(zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 300)), // ...every 5 min - zwave.configurationV1.configurationSet(parameterNumber: 90, size: 1, scaledConfigurationValue: 1).format(), // enabling automatic reports... - zwave.configurationV1.configurationSet(parameterNumber: 91, size: 2, scaledConfigurationValue: 10).format() // ...every 10W change + encap(zwave.configurationV1.configurationSet(parameterNumber: 90, size: 1, scaledConfigurationValue: 0)), // enabling automatic reports, disabled selective reporting... + encap(zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: 0)) //disable CRC16 encapsulation ], 500) else if (isQubinoSmartMeter()) delayBetween([ @@ -184,7 +185,7 @@ def configure() { private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { cmd.format() @@ -213,4 +214,4 @@ private isAeotecHomeEnergyMeter() { private isQubinoSmartMeter() { zwaveInfo.model.equals("0052") -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy b/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy index 65798e644f2..66e26f71c79 100644 --- a/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy +++ b/devicetypes/smartthings/aeon-illuminator-module.src/aeon-illuminator-module.groovy @@ -23,7 +23,7 @@ metadata { command "reset" - fingerprint deviceId: "0x1104", inClusters: "0x26,0x32,0x27,0x2C,0x2B,0x70,0x85,0x72,0x86", outClusters: "0x82" + fingerprint deviceId: "0x1104", inClusters: "0x26,0x32,0x27,0x2C,0x2B,0x70,0x85,0x72,0x86", outClusters: "0x82", deviceJoinName: "Aeon Dimmer Switch" } simulator { diff --git a/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy b/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy index fbb19db11e6..5c54b5e3e51 100644 --- a/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy +++ b/devicetypes/smartthings/aeon-key-fob.src/aeon-key-fob.groovy @@ -13,7 +13,7 @@ import groovy.json.JsonOutput * */ metadata { - definition (name: "Aeon Key Fob", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, ocfDeviceType: "x.com.st.d.remotecontroller") { + definition (name: "Aeon Key Fob", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, ocfDeviceType: "x.com.st.d.remotecontroller", mnmn: "SmartThings", vid: "generic-4-button", mcdSync: true) { capability "Actuator" capability "Button" capability "Holdable Button" @@ -22,9 +22,8 @@ metadata { capability "Battery" capability "Health Check" - fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85" - fingerprint mfr: "0086", prod: "0101", model: "0058", deviceJoinName: "Aeotec Key Fob" - fingerprint mfr: "0086", prod: "0001", model: "0026", deviceJoinName: "Aeotec Panic Button" + fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85", deviceJoinName: "Aeon Remote Control" + fingerprint mfr: "0086", prod: "0001", model: "0026", deviceJoinName: "Aeotec Button", mnmn: "SmartThings", vid: "generic-button-2" //Aeotec Panic Button } simulator { @@ -170,7 +169,7 @@ def installed() { initialize() Integer buttons = (device.currentState("numberOfButtons").value).toBigInteger() - if (buttons > 1) { + if (buttons > 1 && !childDevices) { // Clicking "Update" from the Graph IDE calls installed(), so protect against trying to recreate children. createChildDevices() } } diff --git a/devicetypes/smartthings/aeon-led-bulb-6.src/aeon-led-bulb-6.groovy b/devicetypes/smartthings/aeon-led-bulb-6.src/aeon-led-bulb-6.groovy index 80db31909fc..96b00b88c68 100644 --- a/devicetypes/smartthings/aeon-led-bulb-6.src/aeon-led-bulb-6.groovy +++ b/devicetypes/smartthings/aeon-led-bulb-6.src/aeon-led-bulb-6.groovy @@ -27,9 +27,6 @@ metadata { capability "Sensor" capability "Health Check" capability "Configuration" - - fingerprint mfr: "0371", prod: "0103", model: "0002", deviceJoinName: "Aeon LED Bulb 6 Multi-Color" //US - fingerprint mfr: "0371", prod: "0003", model: "0002", deviceJoinName: "Aeon LED Bulb 6 Multi-Color" //EU } simulator { @@ -281,7 +278,7 @@ private crcEncap(physicalgraph.zwave.Command cmd) { private command(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { cmd.format() diff --git a/devicetypes/smartthings/aeon-led-bulb.src/aeon-led-bulb.groovy b/devicetypes/smartthings/aeon-led-bulb.src/aeon-led-bulb.groovy index e679976ac72..ef21d83aa45 100644 --- a/devicetypes/smartthings/aeon-led-bulb.src/aeon-led-bulb.groovy +++ b/devicetypes/smartthings/aeon-led-bulb.src/aeon-led-bulb.groovy @@ -27,10 +27,6 @@ metadata { capability "Sensor" command "reset" - - fingerprint inClusters: "0x26,0x33,0x98" - fingerprint deviceId: "0x11", inClusters: "0x98,0x33" - fingerprint deviceId: "0x1102", inClusters: "0x98" } simulator { diff --git a/devicetypes/smartthings/aeon-minimote.src/aeon-minimote.groovy b/devicetypes/smartthings/aeon-minimote.src/aeon-minimote.groovy index 5c5ce90153c..a796d4acdb2 100644 --- a/devicetypes/smartthings/aeon-minimote.src/aeon-minimote.groovy +++ b/devicetypes/smartthings/aeon-minimote.src/aeon-minimote.groovy @@ -14,7 +14,7 @@ import groovy.json.JsonOutput * */ metadata { - definition (name: "Aeon Minimote", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, mcdSync: true) { + definition (name: "Aeon Minimote", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, mcdSync: true, ocfDeviceType: "x.com.st.d.remotecontroller") { capability "Actuator" capability "Button" capability "Holdable Button" @@ -22,7 +22,7 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint mfr: "0086", prod: "0001", model:"0003" + fingerprint mfr: "0086", prod: "0001", model:"0003", deviceJoinName: "Aeon Remote Control" } simulator { @@ -120,7 +120,9 @@ def configure() { def installed() { initialize() - createChildDevices() + if (!childDevices) { + createChildDevices() + } } def updated() { diff --git a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy index da0bc354964..80faf0a0e64 100644 --- a/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy +++ b/devicetypes/smartthings/aeon-multisensor-6.src/aeon-multisensor-6.groovy @@ -28,10 +28,10 @@ metadata { attribute "batteryStatus", "string" - fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A" - fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A" - fingerprint mfr: "0086", prod: "0102", model: "0064", deviceJoinName: "Aeotec MultiSensor 6" - fingerprint mfr: "0086", prod: "0202", model: "0064", deviceJoinName: "Aeotec MultiSensor 6" //AU + fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A", deviceJoinName: "Aeon Multipurpose Sensor" + fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A", deviceJoinName: "Aeon Multipurpose Sensor" + fingerprint mfr: "0086", prod: "0102", model: "0064", deviceJoinName: "Aeotec Multipurpose Sensor" //Aeotec MultiSensor 6 + fingerprint mfr: "0086", prod: "0202", model: "0064", deviceJoinName: "Aeotec Multipurpose Sensor" //AU //Aeotec MultiSensor 6 } simulator { @@ -443,7 +443,7 @@ def configure() { def checkInterval = 2 * (timeOptionValueMap[reportInterval] ?: 60 * 60) + 2 * 60 sendEvent(name: "checkInterval", value: checkInterval, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - commands(request, (state.sec || zwaveInfo?.zw?.endsWith("s")) ? 2000 : 500) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] + commands(request, (state.sec || zwaveInfo?.zw?.contains("s")) ? 2000 : 500) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } @@ -476,7 +476,7 @@ private isConfigured() { } private command(physicalgraph.zwave.Command cmd) { - if (state.sec || zwaveInfo?.zw?.endsWith("s")) { + if (state.sec || zwaveInfo?.zw?.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() diff --git a/devicetypes/smartthings/aeon-multisensor-gen5.src/aeon-multisensor-gen5.groovy b/devicetypes/smartthings/aeon-multisensor-gen5.src/aeon-multisensor-gen5.groovy index 9e596cabab8..09f1f4b8045 100644 --- a/devicetypes/smartthings/aeon-multisensor-gen5.src/aeon-multisensor-gen5.groovy +++ b/devicetypes/smartthings/aeon-multisensor-gen5.src/aeon-multisensor-gen5.groovy @@ -22,8 +22,8 @@ metadata { capability "Battery" capability "Health Check" - fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A" - fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeotec MultiSensor (Gen 5)" + fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A", deviceJoinName: "Aeon Multipurpose Sensor" + fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeotec Multipurpose Sensor" //Aeotec MultiSensor (Gen 5) } simulator { diff --git a/devicetypes/smartthings/aeon-multisensor.src/aeon-multisensor.groovy b/devicetypes/smartthings/aeon-multisensor.src/aeon-multisensor.groovy index 2b797eafe3f..d574011a8a5 100644 --- a/devicetypes/smartthings/aeon-multisensor.src/aeon-multisensor.groovy +++ b/devicetypes/smartthings/aeon-multisensor.src/aeon-multisensor.groovy @@ -22,7 +22,7 @@ metadata { capability "Battery" capability "Health Check" - fingerprint deviceId: "0x2001", inClusters: "0x30,0x31,0x80,0x84,0x70,0x85,0x72,0x86" + fingerprint deviceId: "0x2001", inClusters: "0x30,0x31,0x80,0x84,0x70,0x85,0x72,0x86", deviceJoinName: "Aeon Multipurpose Sensor" } simulator { diff --git a/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy b/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy index aed61031d40..a70ac96e6ff 100644 --- a/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy +++ b/devicetypes/smartthings/aeon-multiwhite-bulb.src/aeon-multiwhite-bulb.groovy @@ -28,9 +28,9 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint mfr: "0371", prod: "0103", model: "0001", deviceJoinName: "Aeon LED Bulb 6 Multi-White" //US - fingerprint mfr: "0371", prod: "0003", model: "0001", deviceJoinName: "Aeon LED Bulb 6 Multi-White" //EU - fingerprint mfr: "0300", prod: "0003", model: "0004", deviceJoinName: "ilumin Tunable White" + fingerprint mfr: "0371", prod: "0103", model: "0001", deviceJoinName: "Aeon Light" //US //Aeon LED Bulb 6 Multi-White + fingerprint mfr: "0371", prod: "0003", model: "0001", deviceJoinName: "Aeon Light" //EU //Aeon LED Bulb 6 Multi-White + fingerprint mfr: "0300", prod: "0003", model: "0004", deviceJoinName: "ilumin Light" //ilumin Tunable White } simulator { @@ -184,7 +184,7 @@ def setLevel(level, duration) { commands([ zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: duration), zwave.switchMultilevelV3.switchMultilevelGet(), - ], (duration && duration < 12) ? (duration * 1000) : 3500) + ], (duration && duration < 12) ? (duration * 1000 + 2000) : 3500) } def setColorTemperature(temp) { @@ -217,7 +217,7 @@ private crcEncap(physicalgraph.zwave.Command cmd) { private command(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { cmd.format() diff --git a/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy b/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy index 53db9bfc7b9..f828c411825 100644 --- a/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy +++ b/devicetypes/smartthings/aeon-outlet.src/aeon-outlet.groovy @@ -22,7 +22,7 @@ metadata { command "reset" - fingerprint deviceId: "0x1001", inClusters: "0x25,0x32,0x27,0x2C,0x2B,0x70,0x85,0x56,0x72,0x86", outClusters: "0x82" + fingerprint deviceId: "0x1001", inClusters: "0x25,0x32,0x27,0x2C,0x2B,0x70,0x85,0x56,0x72,0x86", outClusters: "0x82", deviceJoinName: "Aeon Outlet" } // simulator metadata diff --git a/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy b/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy index fe4e8d201df..52afc28db10 100644 --- a/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy +++ b/devicetypes/smartthings/aeon-siren.src/aeon-siren.groovy @@ -24,7 +24,7 @@ metadata { command "test" - fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98", deviceJoinName: "Aeotec Siren (Gen 5)" + fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98", deviceJoinName: "Aeotec Siren" //Aeotec Siren (Gen 5) } simulator { diff --git a/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy b/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy index 702885d5095..fd506d75300 100644 --- a/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy +++ b/devicetypes/smartthings/aeon-smartstrip.src/aeon-smartstrip.groovy @@ -32,7 +32,7 @@ metadata { command "reset$n" } - fingerprint deviceId: "0x1001", inClusters: "0x25,0x32,0x27,0x70,0x85,0x72,0x86,0x60", outClusters: "0x82" + fingerprint deviceId: "0x1001", inClusters: "0x25,0x32,0x27,0x70,0x85,0x72,0x86,0x60", outClusters: "0x82", deviceJoinName: "Aeon Outlet" } // simulator metadata @@ -124,6 +124,14 @@ def endpointEvent(endpoint, map) { } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) if (encapsulatedCommand) { if (encapsulatedCommand.commandClassId == 0x32) { diff --git a/devicetypes/smartthings/aeotec-doorbell-siren-6.src/aeotec-doorbell-siren-6.groovy b/devicetypes/smartthings/aeotec-doorbell-siren-6.src/aeotec-doorbell-siren-6.groovy new file mode 100644 index 00000000000..74666828740 --- /dev/null +++ b/devicetypes/smartthings/aeotec-doorbell-siren-6.src/aeotec-doorbell-siren-6.groovy @@ -0,0 +1,353 @@ +/** + * Aeotec Doorbell 6 + * + * Copyright 2020 SmartThings + * + * 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: "Aeotec Doorbell Siren 6", namespace: "smartthings", author: "SmartThings", mcdSync: true) { + capability "Actuator" + capability "Health Check" + capability "Tamper Alert" + capability "Alarm" + capability "Chime" + + fingerprint mfr: "0371", prod: "0003", model: "00A2", deviceJoinName: "Aeotec Doorbell", ocfDeviceType: "x.com.st.d.doorbell" //EU //Aeotec Doorbell 6 + fingerprint mfr: "0371", prod: "0103", model: "00A2", deviceJoinName: "Aeotec Doorbell", ocfDeviceType: "x.com.st.d.doorbell" //US //Aeotec Doorbell 6 + fingerprint mfr: "0371", prod: "0203", model: "00A2", deviceJoinName: "Aeotec Doorbell", ocfDeviceType: "x.com.st.d.doorbell" //AU //Aeotec Doorbell 6 + fingerprint mfr: "0371", prod: "0003", model: "00A4", deviceJoinName: "Aeotec Siren", ocfDeviceType: "x.com.st.d.siren" //EU //Aeotec Siren 6 + fingerprint mfr: "0371", prod: "0103", model: "00A4", deviceJoinName: "Aeotec Siren", ocfDeviceType: "x.com.st.d.siren" //US //Aeotec Siren 6 + fingerprint mfr: "0371", prod: "0203", model: "00A4", deviceJoinName: "Aeotec Siren", ocfDeviceType: "x.com.st.d.siren" //AU //Aeotec Siren 6 + } + + tiles { + multiAttributeTile(name: "alarm", type: "generic", width: 6, height: 4) { + tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { + attributeState "off", label: 'off', action: 'alarm.siren', icon: "st.alarm.alarm.alarm", backgroundColor: "#ffffff" + attributeState "both", label: 'ring!', action: 'alarm.off', icon: "st.alarm.alarm.alarm", backgroundColor: "#0e7507" + } + } + standardTile("off", "device.alarm", inactiveLabel: false, decoration: "flat") { + state "default", label: '', action: "alarm.off", icon: "st.secondary.off" + } + valueTile("tamper", "device.tamper", height: 2, width: 2, decoration: "flat") { + state "clear", label: 'tamper clear', backgroundColor: "#ffffff" + state "detected", label: 'tampered', backgroundColor: "#ffffff" + } + standardTile("refresh", "command.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "refresh", label: '', action: "refresh.refresh", icon: "st.secondary.refresh-icon" + } + + main "alarm" + details(["alarm", "off", "tamper", "refresh"]) + } + + preferences { + section { + input(title: "Control Sound and Volume", + description: "Follow these steps to adjust sound/volume: 1. Set Endpoint, 2. Set Volume, 3. Set Sound, 4. Toggle button to ON, 5. Wait five seconds before new configuration or use, 6. Close setting page to refresh button or toggle button OFF", + displayDuringSetup: false, + type: "paragraph", + element: "paragraph") + + //Endpoint variable + input(title: "Endpoint Explanation", + description: "Determines which endpoint to control. 1 = Browse, 2 = Tamper, 3 = Button one, 4 = Button two, 5 = Button three, 6 = Environment, 7 = Security, 8 = Emergency", + displayDuringSetup: false, + type: "paragraph", + element: "paragraph") + input("sirenDoorbellEndpoint", "number", + title: "1. Endpoint", + default: 2, + range: "1..8", + displayDuringSetup: false) + + //Volume level variable + input("sirenDoorbellVolume", "number", + title: "2. Volume set in %", + default: 30, + range: "0..100", + displayDuringSetup: false) + + //SoundID variable + input("sirenDoorbellSound", "number", + title: "3. Sound #", + default: 17, + range: "1..30", + displayDuringSetup: false) + + //Will not send sound/volume to reduce z-wave traffic until (SirenDoorbellSend == true) + //SirenDoorbellSend will toggle back to false when settings page is closed. + input("sirenDoorbellSend", "bool", + title: "4. Send sound and volume configuration", + default: false, + displayDuringSetup: false) + } + } +} + +private getNumberOfSounds() { + def numberOfSounds = [ + "0003" : 8, //Aeotec Doorbell/Siren EU + "0103" : 8, //Aeotec Doorbell/Siren US + "0203" : 8 //Aeotec Doorbell/Siren AU + ] + return numberOfSounds[zwaveInfo.prod] ?: 1 +} + +def installed() { + initialize() + sendEvent(name: "alarm", value: "off", isStateChange: true, displayed: false) + sendEvent(name: "chime", value: "off", isStateChange: true, displayed: false) + sendEvent(name: "tamper", value: "clear", isStateChange: true, displayed: false) + soundControl(2, 30, 17) //adjust the tamper volume to be lower than default when initially paired. +} + +def updated() { + initialize() + //keep Z-Wave traffic low, requires bool button in setting to trigger. + if (sirenDoorbellSend == true) { + soundControl(sirenDoorbellEndpoint, sirenDoorbellVolume, sirenDoorbellSound) + } +} + +def soundControl(endpoint, volume, sound) { + if (endpoint && volume && sound) { + mcEncap(zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint, commandClass:0x79, command:0x05, parameter: [volume,sound])) + } else { + log.debug "endpoint, volume, or sound settings is null" + } +} + +def initialize() { + if (!childDevices) { + addChildren(numberOfSounds) + } + sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + +def parse(String description) { + def result = null + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } + log.debug "Parse returned: ${result.inspect()}" + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + log.debug ""+cmd + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + + def encapsulatedCommand = cmd.encapsulatedCommand([0x60: 3]) + def endpoint = cmd.sourceEndPoint + + if (cmd.commandClass == 0x71) { + state.lastTriggeredSound = endpoint //notification cc determines sound is triggered + } + + if (endpoint == state.lastTriggeredSound && encapsulatedCommand != null) { + return zwaveEvent(encapsulatedCommand) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def securedEncapsulatedCommand = cmd.securedEncapsulatedCommand([0x60: 3]) + if (securedEncapsulatedCommand) { + zwaveEvent(securedEncapsulatedCommand) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +private onOffCmd(value) { + encap(zwave.basicV1.basicSet(value: value)) +} + +def on() { + resetActiveSound() + state.lastTriggeredSound = 1 + onOffCmd(0xFF) +} + +def off() { + state.lastTriggeredSound = 1 + onOffCmd(0x00) +} + +def strobe() { + on() +} + +def siren() { + on() +} + +def both() { + on() +} + +def chime() { + on() +} + +def ping() { + def cmds = [ + encap(zwave.basicV1.basicGet()) + ] + sendHubCommand(cmds) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + if (cmd.value == 0) { + keepChildrenOnline() + sendEvent(name: "alarm", value: "off") + sendEvent(name: "chime", value: "off") + } +} + +def refresh() { + ping() +} + +private addChildren(numberOfSounds) { + for (def endpoint : 2..numberOfSounds) { + try { + String childDni = "${device.deviceNetworkId}:$endpoint" + + addChildDevice("Aeotec Doorbell Siren Child", childDni, device.getHub().getId(), [ + completedSetup: true, + label : "$device.displayName Sound $endpoint", + isComponent : true, + componentName : "sound$endpoint", + componentLabel: "Sound $endpoint" + ]) + } catch (Exception e) { + log.debug "Excep: ${e} " + } + } +} + +def channelNumber(String dni) { + dni[-1] as Integer +} + +def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + if (cmd.notificationStatus == 0xFF) { + switch (cmd.event) { + case 0x09: //TAMPER + sendEvent(name: "tamper", value: "detected") + sendEvent(name: "alarm", value: "both") + runIn(2, "clearTamperAndAlarm") + break + case 0x01: //ON + if (state.lastTriggeredSound == 1) { + sendEvent(name: "chime", value: "chime") + sendEvent(name: "alarm", value: "both") + } else { + setActiveSound(state.lastTriggeredSound) + } + break + case 0x00: //OFF + resetActiveSound() + sendEvent(name: "tamper", value: "clear") + sendEvent(name: "alarm", value: "off") + sendEvent(name: "chime", value: "off") + break + } + } +} + +def clearTamperAndAlarm() { + sendEvent(name: "tamper", value: "clear") + sendEvent(name: "alarm", value: "off") +} + +def setOnChild(deviceDni) { + resetActiveSound() + sendHubCommand encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(deviceDni)) + state.lastTriggeredSound = channelNumber(deviceDni) + setActiveSound(state.lastTriggeredSound) +} + +def setOffChild(deviceDni) { + sendHubCommand encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(deviceDni)) +} + +def resetActiveSound() { + if (state.lastTriggeredSound > 1) { + String childDni = "${device.deviceNetworkId}:$state.lastTriggeredSound" + def child = childDevices.find { it.deviceNetworkId == childDni } + + setOffChild(childDni) + child?.sendEvent([name: "chime", value: "off"]) + child?.sendEvent([name: "alarm", value: "off"]) + } else { + sendHubCommand(onOffCmd(0x00)) + } + sendEvent([name: "alarm", value: "off"]) + sendEvent([name: "chime", value: "off"]) +} + +def setActiveSound(soundId) { + String childDni = "${device.deviceNetworkId}:${soundId}" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(name: "chime", value: "chime") + child?.sendEvent(name: "alarm", value: "both") +} + +def keepChildrenOnline() { + /* + Method to make children online when checkInterval will be called. + */ + for (def i : 2..numberOfSounds) { + def soundNumber = i + String childDni = "${device.deviceNetworkId}:$soundNumber" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(name: "chime", value: "off") + child?.sendEvent(name: "alarm", value: "off") + } +} + +private encap(cmd, endpoint = null) { + if (cmd) { + log.debug "encap: "+cmd + if (endpoint && endpoint > 1) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private mcEncap(cmd) { + if (cmd) { + if (zwaveInfo.zw.contains("s")) { + device.updateSetting("sirenDoorbellSend", [value:"false",type:"bool"]) //reset preference toggle button when leaving setting page + return response(zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()) //used to process Sound Switch Configuration SET + } else { + cmd.format() + } + } +} diff --git a/devicetypes/smartthings/aeotec-doorbell-siren-child.src/aeotec-doorbell-siren-child.groovy b/devicetypes/smartthings/aeotec-doorbell-siren-child.src/aeotec-doorbell-siren-child.groovy new file mode 100644 index 00000000000..16e2b815561 --- /dev/null +++ b/devicetypes/smartthings/aeotec-doorbell-siren-child.src/aeotec-doorbell-siren-child.groovy @@ -0,0 +1,72 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Aeotec Doorbell Siren Child", namespace: "smartthings", author: "SmartThings") { + capability "Actuator" + capability "Health Check" + capability "Alarm" + capability "Chime" + + } + tiles { + multiAttributeTile(name: "chime", type: "generic", width: 6, height: 2) { + tileAttribute("device.chime", key: "PRIMARY_CONTROL") { + attributeState "off", label: 'chime', action: 'chime.chime', icon: "st.alarm.alarm.alarm", backgroundColor: "#ffffff" + attributeState "chime", label: 'off', action: 'chime.off', icon: "st.alarm.alarm.alarm", backgroundColor: "#ff0000" + } + } + multiAttributeTile(name: "alarm", type: "generic", width: 6, height: 2) { + tileAttribute("device.alarm", key: "PRIMARY_CONTROL") { + attributeState "off", label: 'off', action: 'alarm.siren', icon: "st.alarm.alarm.alarm", backgroundColor: "#ffffff" + attributeState "both", label: 'alarm', action: 'alarm.off', icon: "st.alarm.alarm.alarm", backgroundColor: "#ff0000" + } + } + standardTile("off", "device.chime", inactiveLabel: false, decoration: "flat") { + state "default", label: '', action: "chime.off", icon: "st.secondary.off" + } + + main "chime" + details(["chime", "alarm", "off"]) + } +} + +def installed() { + sendEvent(name: "chime", value: "off", isStateChange: true, displayed: false) + sendEvent(name: "alarm", value: "off", isStateChange: true, displayed: false) + sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false) +} + +def off() { + parent.setOffChild(device.deviceNetworkId) +} + +def on() { + parent.setOnChild(device.deviceNetworkId) +} + +def chime() { + on() +} + +def strobe() { + on() +} + +def siren() { + on() +} + +def both() { + on() +} \ No newline at end of file diff --git a/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy b/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy index 1c91a27b9e9..9de9492599a 100644 --- a/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy +++ b/devicetypes/smartthings/aeotec-wallmote.src/aeotec-wallmote.groovy @@ -19,13 +19,13 @@ metadata { capability "Actuator" capability "Button" capability "Battery" - capability "Holdable Button" capability "Configuration" capability "Sensor" capability "Health Check" - fingerprint mfr: "0086", model: "0082", deviceJoinName: "Aeotec Wallmote Quad", mnmn: "SmartThings", vid: "generic-4-button" - fingerprint mfr: "0086", model: "0081", deviceJoinName: "Aeotec Wallmote", mnmn: "SmartThings", vid: "generic-2-button" + fingerprint mfr: "0086", model: "0082", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Aeotec Wallmote Quad + fingerprint mfr: "0086", model: "0081", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Aeotec Wallmote + fingerprint mfr: "0060", model: "0003", deviceJoinName: "Everspring Remote Control", mnmn: "SmartThings", vid: "generic-2-button" //Everspring Wall Switch } tiles(scale: 2) { @@ -44,14 +44,14 @@ metadata { } def getNumberOfButtons() { - def modelToButtons = ["0082" : 4, "0081": 2] + def modelToButtons = ["0082" : 4, "0081": 2, "0003": 2] return modelToButtons[zwaveInfo.model] ?: 1 } def installed() { createChildDevices() sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false) - sendEvent(name: "supportedButtonValues", value: ["pushed", "held"].encodeAsJson(), displayed: false) + sendEvent(name: "supportedButtonValues", value: supportedButtonValues.encodeAsJson(), displayed: false) sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], displayed: false) } @@ -90,17 +90,13 @@ def parse(String description) { def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { def button = cmd.sceneNumber - def value - // 0 = pushed, 1 = released, 2 = held down - if (cmd.keyAttributes != 2) { - value = cmd.keyAttributes == 1 ? "held" : "pushed" - } else { - // we can't do anything with the held down event yet - return [] + + def value = buttonAttributesMap[(int)cmd.keyAttributes] + if (value) { + def child = getChildDevice(button) + child?.sendEvent(name: "button", value: value, data: [buttonNumber: 1], descriptionText: "$child.displayName was $value", isStateChange: true) + createEvent(name: "button", value: value, data: [buttonNumber: button], descriptionText: "$device.displayName button $button was $value", isStateChange: true, displayed: false) } - def child = getChildDevice(button) - child?.sendEvent(name: "button", value: value, data: [buttonNumber: 1], descriptionText: "$child.displayName was $value", isStateChange: true) - createEvent(name: "button", value: value, data: [buttonNumber: button], descriptionText: "$device.displayName button $button was $value", isStateChange: true) } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { @@ -149,14 +145,14 @@ def createChildDevices() { child = addChildDevice("Child Button", "${device.deviceNetworkId}:${i}", device.hubId, [completedSetup: true, label: "${device.displayName} button ${i}", isComponent: true, componentName: "button$i", componentLabel: "Button $i"]) - child.sendEvent(name: "supportedButtonValues", value: ["pushed", "held"].encodeAsJson(), displayed: false) + child.sendEvent(name: "supportedButtonValues", value: supportedButtonValues.encodeAsJson(), displayed: false) child.sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "$child.displayName was pushed", isStateChange: true, displayed: false) } } } def secure(cmd) { - if (zwaveInfo.zw.endsWith("s")) { + if (zwaveInfo.zw.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() @@ -170,4 +166,30 @@ def getChildDevice(button) { log.error "Child device $childDni not found" } return child -} \ No newline at end of file +} + +private getSupportedButtonValues() { + if (isEverspring()) { + return ["pushed", "held", "double"] + } else { + return ["pushed", "held"] + } +} + +private getButtonAttributesMap() { + if (isEverspring()) {[ + 0: "pushed", + 2: "held", + 3: "double" + ]} + else {[ + 0: "pushed", + 1: "held" + ]} +} + +private isEverspring() { + zwaveInfo.model.equals("0003") +} + + diff --git a/devicetypes/smartthings/arrival-sensor-ha.src/arrival-sensor-ha.groovy b/devicetypes/smartthings/arrival-sensor-ha.src/arrival-sensor-ha.groovy index e9ddbbccc02..c0f1266f6ca 100644 --- a/devicetypes/smartthings/arrival-sensor-ha.src/arrival-sensor-ha.groovy +++ b/devicetypes/smartthings/arrival-sensor-ha.src/arrival-sensor-ha.groovy @@ -24,8 +24,7 @@ metadata { capability "Configuration" capability "Health Check" - fingerprint inClusters: "0000,0001,0003,000F,0020", outClusters: "0003,0019", - manufacturer: "SmartThings", model: "tagv4", deviceJoinName: "Arrival Sensor" + fingerprint inClusters: "0000,0001,0003,000F,0020", outClusters: "0003,0019", manufacturer: "SmartThings", model: "tagv4", deviceJoinName: "SmartThings Presence Sensor" } preferences { diff --git a/devicetypes/smartthings/arrival-sensor-ha.src/i18n/messages.properties b/devicetypes/smartthings/arrival-sensor-ha.src/i18n/messages.properties index c5fd0c700d5..75cdb81e9be 100644 --- a/devicetypes/smartthings/arrival-sensor-ha.src/i18n/messages.properties +++ b/devicetypes/smartthings/arrival-sensor-ha.src/i18n/messages.properties @@ -15,9 +15,8 @@ # Device Preferences '''Give your device a name'''.ko=기기 이름 설정 '''Set Device Image'''.ko=기기 이미지 설정 -'''Presence timeout (minutes)'''.ko=알람 유예 시간 설정 (분) -'''Tap to set'''.ko=눌러서 설정 '''Arrival Sensor'''.ko=도착알림 센서 +'''SmartThings Presence Sensor'''.ko=도착알림 센서 '''${currentValue}% battery'''.ko=${currentValue}% 배터리 # Events / Notifications '''{{ linkText }} battery was {{ value }}'''.ko={{ linkText }}의 남은 배터리 {{ value }} diff --git a/devicetypes/smartthings/arrival-sensor.src/arrival-sensor.groovy b/devicetypes/smartthings/arrival-sensor.src/arrival-sensor.groovy index fa674f9d0fe..b2bd063f616 100644 --- a/devicetypes/smartthings/arrival-sensor.src/arrival-sensor.groovy +++ b/devicetypes/smartthings/arrival-sensor.src/arrival-sensor.groovy @@ -23,9 +23,9 @@ metadata { capability "Battery" capability "Health Check" - fingerprint profileId: "FC01", deviceId: "019A" - fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003" - fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000", outClusters: "0006" + fingerprint profileId: "FC01", deviceId: "019A", deviceJoinName: "SmartThings Presence Sensor" + fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003", deviceJoinName: "SmartThings Presence Sensor" + fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000", outClusters: "0006", deviceJoinName: "SmartThings Presence Sensor" } simulator { diff --git a/devicetypes/smartthings/centralite-thermostat.src/centralite-thermostat.groovy b/devicetypes/smartthings/centralite-thermostat.src/centralite-thermostat.groovy index bf5f320323f..4954b690cf5 100644 --- a/devicetypes/smartthings/centralite-thermostat.src/centralite-thermostat.groovy +++ b/devicetypes/smartthings/centralite-thermostat.src/centralite-thermostat.groovy @@ -24,7 +24,7 @@ metadata { capability "Refresh" capability "Sensor" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0201,0202,0204,0B05", outClusters: "000A, 0019" + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0201,0202,0204,0B05", outClusters: "000A, 0019", deviceJoinName: "Centralite Thermostat" } // simulator metadata diff --git a/devicetypes/smartthings/child-button.src/child-button.groovy b/devicetypes/smartthings/child-button.src/child-button.groovy index e365066a903..fa05548903c 100644 --- a/devicetypes/smartthings/child-button.src/child-button.groovy +++ b/devicetypes/smartthings/child-button.src/child-button.groovy @@ -14,7 +14,7 @@ * */ metadata { - definition (name: "Child Button", namespace: "smartthings", author: "SmartThings") { + definition (name: "Child Button", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.remotecontroller") { capability "Button" capability "Holdable Button" capability "Sensor" diff --git a/devicetypes/smartthings/child-color-control.src/child-color-control.groovy b/devicetypes/smartthings/child-color-control.src/child-color-control.groovy new file mode 100644 index 00000000000..38d90a05d88 --- /dev/null +++ b/devicetypes/smartthings/child-color-control.src/child-color-control.groovy @@ -0,0 +1,37 @@ +/* Copyright 2020 SmartThings +* +* 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. +* +* Child Color Selection +* +* Copyright 2020 SmartThings +* +*/ +metadata { + definition(name: "Child Color Control", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings") { + capability "Color Control" + capability "Actuator" + } + + tiles(scale: 2){ + multiAttributeTile(name:"switch", type: "generic", width: 6, height: 4, canChangeIcon: true){ + tileAttribute ("device.color", key: "COLOR_CONTROL") { + attributeState "color", action:"setColor" + } + } + + main(["switch"]) + details(["switch"]) + } +} + +def setColor(value) { + parent.childSetColor(value) +} diff --git a/devicetypes/smartthings/child-contact-sensor.src/child-contact-sensor.groovy b/devicetypes/smartthings/child-contact-sensor.src/child-contact-sensor.groovy new file mode 100644 index 00000000000..df5502acdaa --- /dev/null +++ b/devicetypes/smartthings/child-contact-sensor.src/child-contact-sensor.groovy @@ -0,0 +1,57 @@ +/** + * Copyright 2019 SmartThings, RBoy Apps + * + * 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: "Child Contact Sensor", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-contact", ocfDeviceType: "x.com.st.d.sensor.contact") { + capability "Contact Sensor" + capability "Sensor" + capability "Health Check" + } + + tiles(scale: 2) { + multiAttributeTile(name: "contact", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.contact", key: "PRIMARY_CONTROL") { + attributeState("open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13") + attributeState("closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC") + } + } + + main "contact" + details(["contact"]) + } +} + +def installed() { + configure() +} + +def updated() { + configure() +} + +def configure() { + parent.configureChild() + refresh() +} + +def ping() { + refresh() +} + +def refresh() { + parent.refreshChild() +} + +def uninstalled() { + parent.deleteChild() +} diff --git a/devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy b/devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy new file mode 100644 index 00000000000..a182b0c19a8 --- /dev/null +++ b/devicetypes/smartthings/child-energy-meter.src/child-energy-meter.groovy @@ -0,0 +1,50 @@ +/** + * Copyright 2020 SRPOL + * + * 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: "Child Energy Meter", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-switch-power-energy") { + capability "Power Meter" + capability "Energy Meter" + capability "Refresh" + capability "Actuator" + capability "Sensor" + capability "Health Check" + } + + tiles(scale: 2) { + valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} W' + } + valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) { + state "default", label:'${currentValue} kWh' + } + standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" + } + + main(["switch"]) + details(["power","energy","refresh"]) + } +} + +def refresh() { + parent.childRefresh(device.deviceNetworkId) +} + +def ping() { + refresh() +} + +def installed() { + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [hubHardwareId: device.hub.hardwareID]) +} \ No newline at end of file diff --git a/devicetypes/smartthings/child-switch-multilevel.src/child-switch-multilevel.groovy b/devicetypes/smartthings/child-switch-multilevel.src/child-switch-multilevel.groovy new file mode 100644 index 00000000000..8aeb35bd32c --- /dev/null +++ b/devicetypes/smartthings/child-switch-multilevel.src/child-switch-multilevel.groovy @@ -0,0 +1,39 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Child Switch Multilevel", namespace: "smartthings", author: "SmartThings") { + capability "Switch Level" + capability "Actuator" + capability "Sensor" + } + + tiles(scale: 2) { + valueTile("level", "device.level", width: 4, height: 1) { + state "level", label: 'Level: ${currentValue}% ', defaultState: true + } + + main "level" + details(["level"]) + } +} + +def installed() { + parent.multilevelChildInstalled(device.deviceNetworkId) +} + +def setLevel(level) { + def currentLevel = Integer.parseInt(device.currentState("level").value) + parent.setLevelChild(level, device.deviceNetworkId, currentLevel) +} diff --git a/devicetypes/smartthings/child-temperature-sensor.src/child-temperature-sensor.groovy b/devicetypes/smartthings/child-temperature-sensor.src/child-temperature-sensor.groovy index aedc2a906a2..b972a66c628 100644 --- a/devicetypes/smartthings/child-temperature-sensor.src/child-temperature-sensor.groovy +++ b/devicetypes/smartthings/child-temperature-sensor.src/child-temperature-sensor.groovy @@ -18,6 +18,7 @@ metadata { capability "Battery" capability "Health Check" capability "Refresh" + capability "Configuration" } tiles(scale: 2) { diff --git a/devicetypes/smartthings/child-venetian-blind.src/child-venetian-blind.groovy b/devicetypes/smartthings/child-venetian-blind.src/child-venetian-blind.groovy new file mode 100644 index 00000000000..35860d6b558 --- /dev/null +++ b/devicetypes/smartthings/child-venetian-blind.src/child-venetian-blind.groovy @@ -0,0 +1,33 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Child Venetian Blind", namespace: "smartthings", author: "SmartThings") { + capability "Switch Level" + capability "Actuator" + capability "Sensor" + } + + tiles(scale: 2) { + valueTile("slatsLevel", "device.level", width: 4, height: 1) { + state "level", label: 'Slats covers in ${currentValue}% ', defaultState: true + } + + main "slatsLevel" + details(["slatsLevel"]) + } +} + +def setLevel(level) { + parent.setSlats(device.deviceNetworkId, level) +} \ No newline at end of file diff --git a/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy b/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy index 63abf089519..071ed2644ed 100644 --- a/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy +++ b/devicetypes/smartthings/cree-bulb.src/cree-bulb.groovy @@ -25,7 +25,7 @@ metadata { capability "Health Check" capability "Light" - fingerprint manufacturer: "CREE", model: "Connected A-19 60W Equivalent" // 0A C05E 0100 02 07 0000 1000 0004 0003 0005 0006 0008 02 0000 0019 + fingerprint manufacturer: "CREE", model: "Connected A-19 60W Equivalent" , deviceJoinName: "Cree Light"// 0A C05E 0100 02 07 0000 1000 0004 0003 0005 0006 0008 02 0000 0019 } // simulator metadata diff --git a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy index 4851292629f..c5638956b54 100644 --- a/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy +++ b/devicetypes/smartthings/ct100-thermostat.src/ct100-thermostat.groovy @@ -20,9 +20,9 @@ metadata { command "raiseCoolSetpoint" command "poll" - fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60" - fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat" - fingerprint mfr:"0098", prod:"6501", model:"000C", deviceJoinName: "Radio Thermostat CT101" + fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60", deviceJoinName: "Thermostat" + fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig Thermostat" //2Gig CT100 Programmable Thermostat + fingerprint mfr:"0098", prod:"6501", model:"000C", deviceJoinName: "Iris Thermostat" //Radio Thermostat CT101 } tiles { diff --git a/devicetypes/smartthings/danalock.src/danalock.groovy b/devicetypes/smartthings/danalock.src/danalock.groovy index 9e062ff9444..2b5c66cac2e 100644 --- a/devicetypes/smartthings/danalock.src/danalock.groovy +++ b/devicetypes/smartthings/danalock.src/danalock.groovy @@ -20,7 +20,7 @@ metadata { capability "Actuator" capability "Sensor" - fingerprint deviceId: '0x4002', inClusters: '0x72,0x80,0x86,0x98' + fingerprint deviceId: '0x4002', inClusters: '0x72,0x80,0x86,0x98', deviceJoinName: "Danalock Door Lock" } simulator { diff --git a/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy b/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy index 9e5ed0a20b7..2bd3afbde3f 100755 --- a/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy +++ b/devicetypes/smartthings/dawon-zwave-smart-plug.src/dawon-zwave-smart-plug.groovy @@ -24,8 +24,8 @@ metadata { command "reset" - fingerprint mfr: "018C", prod: "0042", model: "0005", deviceJoinName: "Dawon Smart Plug" - fingerprint mfr: "018C", prod: "0042", model: "0008", deviceJoinName: "Dawon Smart Multitab" + fingerprint mfr: "018C", prod: "0042", model: "0005", deviceJoinName: "Dawon Outlet" //Dawon Smart Plug + fingerprint mfr: "018C", prod: "0042", model: "0008", deviceJoinName: "Dawon Outlet" //Dawon Smart Multitab } // simulator metadata diff --git a/devicetypes/smartthings/dawon-zwave-wall-smart-switch.src/dawon-zwave-wall-smart-switch.groovy b/devicetypes/smartthings/dawon-zwave-wall-smart-switch.src/dawon-zwave-wall-smart-switch.groovy new file mode 100644 index 00000000000..19819cabd11 --- /dev/null +++ b/devicetypes/smartthings/dawon-zwave-wall-smart-switch.src/dawon-zwave-wall-smart-switch.groovy @@ -0,0 +1,374 @@ +/** + * Copyright 2020 SmartThings + * + * 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: "Dawon Z-Wave Wall Smart Switch", namespace: "smartthings", author: "SmartThings", mnmn:"SmartThings", vid:"generic-humidity-3") { + + capability "Configuration" + capability "Temperature Measurement" + capability "Relative Humidity Measurement" + capability "Sensor" + capability "Health Check" + + fingerprint mfr: "018C", prod: "0061", model: "0001", deviceJoinName: "Dawon Multipurpose Sensor" // KR // addChildDevice "Dawon Smart Switch${endpoint}" 1 //Dawon Temp/Humidity Sensor + fingerprint mfr: "018C", prod: "0062", model: "0001", deviceJoinName: "Dawon Multipurpose Sensor" // KR // addChildDevice "Dawon Smart Switch${endpoint}" 2 //Dawon Temp/Humidity Sensor + fingerprint mfr: "018C", prod: "0063", model: "0001", deviceJoinName: "Dawon Multipurpose Sensor" // KR // addChildDevice "Dawon Smart Switch${endpoint}" 3 //Dawon Temp/Humidity Sensor + fingerprint mfr: "018C", prod: "0064", model: "0001", deviceJoinName: "Dawon Multipurpose Sensor" // US // addChildDevice "Dawon Smart Switch${endpoint}" 1 //Dawon Temp/Humidity Sensor + fingerprint mfr: "018C", prod: "0065", model: "0001", deviceJoinName: "Dawon Multipurpose Sensor" // US // addChildDevice "Dawon Smart Switch${endpoint}" 2 //Dawon Temp/Humidity Sensor + fingerprint mfr: "018C", prod: "0066", model: "0001", deviceJoinName: "Dawon Multipurpose Sensor" // US // addChildDevice "Dawon Smart Switch${endpoint}" 3 //Dawon Temp/Humidity Sensor + } + + preferences { + input "reportingInterval", "number", title: "Reporting interval", defaultValue: 10, description: "How often the device should report in minutes", range: "1..60", displayDuringSetup: false // default value set to 10 minutes, range 1~60 minutes + //input "tempOffset", "number", title: "Temperature Offset", defaultValue: 2, description: "Adjust temperature by this many degrees", range: "1..100", displayDuringSetup: false // default value 2 °<= Dawon DNS don't want to this configuration item changing for power consumption saving. + //input "humidityOffset", "number", title: "Humidity Offset", defaultValue: 10, description: "Adjust humidity by this percentage", range: "1..100", displayDuringSetup: false // default value 10 % <= Dawon DNS don't want to this configuration item changing for power consumption saving. + } + + tiles(scale: 2) { + multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState "temperature", label: '${currentValue}°', + backgroundColors: [ + [value: 31, color: "#153591"], + [value: 44, color: "#1e9cbb"], + [value: 59, color: "#90d2a7"], + [value: 74, color: "#44b621"], + [value: 84, color: "#f1d801"], + [value: 95, color: "#d04e00"], + [value: 96, color: "#bc2323"] + ] + } + } + valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) { + state "humidity", label: '${currentValue}% humidity', unit: "" + } + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", action: "refresh.refresh", icon: "st.secondary.refresh" + } + + main "temperature", "humidity" + details(["temperature", "humidity", "refresh"]) + } +} + +def installed() { + log.info "Installed called '${device.displayName}', reportingInterval '${reportingInterval}'" + if (reportingInterval != null) { + sendEvent(name: "checkInterval", value: 2 * (reportingInterval as int) + 10 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } else { + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } +} + +def updated() { + log.info "updated called" + configure() +} + +def configure() { + log.info "configure called" + log.debug "configure: reportingInterval '${reportingInterval}'" + if (reportingInterval != null) { + sendEvent(name: "checkInterval", value: 2 * (reportingInterval as int)*60 + 10 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) // (reportingInterval as int)*60 : input value unit is minutes + } else { + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } + def commands = [] + commands << zwave.multiChannelV3.multiChannelEndPointGet() + log.debug "configure: commands '${commands}'" + //log.debug "configure: tempOffset '${tempOffset}'" + //log.debug "configure: humidityOffset '${humidityOffset}'" + + if (reportingInterval != null) { + commands << zwave.configurationV1.configurationSet(parameterNumber: 1, size: 2, scaledConfigurationValue: (reportingInterval as int)*60) // (reportingInterval as int)*60 : input value unit is minutes + } + /* + if (tempOffset != null) { + commands << zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: (tempOffset as int)*10) // 0.1 -> 1 + } + if (humidityOffset != null) { + commands << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: humidityOffset as int) + } + */ + commands << zwave.configurationV1.configurationGet(parameterNumber: 1) + //commands << zwave.configurationV1.configurationGet(parameterNumber: 2) + //commands << zwave.configurationV1.configurationGet(parameterNumber: 3) + + commands << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) // temperature + commands << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) // humidity + + sendCommands(commands,1000) +} + +/** + * Mapping of command classes and associated versions used for this DTH + */ +private getCommandClassVersions() { + [ + 0x20: 1, // Basic + 0x25: 1, // Switch Binary + 0x30: 1, // Sensor Binary + 0x31: 5, // Sensor MultiLevel + 0x56: 1, // Crc16Encap + 0x60: 3, // Multi-Channel + 0x70: 2, // Configuration + 0x98: 1, // Security + 0x71: 3 // Notification + ] +} + +def parse(String description) { + log.info("parse called: description: ${description}") + def result = [] + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + } + return createEvent(result) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, endpoint=null) { + log.info "zwaveEvent BasicReport called: "+cmd +endpoint + def value = cmd.value ? "on" : "off" + endpoint ? changeSwitch(endpoint, value) : [] +} + +def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, endpoint = null) { + log.info "zwaveEvent SwitchBinaryReport called: ${endpoint}, ${cmd.value}" + def value = cmd.value ? "on" : "off" + endpoint ? changeSwitch(endpoint, value) : [] +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd, endpoint = null) { + log.info "zwaveEvent SecurityMessageEncapsulation called: ${cmd}, ${endpoint}" + def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract encapsulatedCommand from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, endpoint = null) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } + log.info "zwaveEvent MultiChannelCmdEncap called: '${cmd}' endpoint '${endpoint}'" + def encapsulatedCommand = cmd.encapsulatedCommand() + log.debug "MultiChannelCmdEncap: encapsulatedCommand '${encapsulatedCommand}'" + zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) +} + +def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd, endpoint = null) { + log.info "zwaveEvent NotificationReport called: cmd: '${cmd}' notificationType: '${cmd.notificationType}', event: '${cmd.event}', endpoint '${endpoint}'" + def result = [] + + if (cmd.notificationType == 0x08) { + def value = cmd.event== 0x03? "on" : "off" + endpoint ? result = changeSwitch(endpoint, value) : [] + } +} + +def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { + log.info "zwaveEvent Crc16Encap called: cmd '${cmd}'" + def versions = commandClassVersions + def version = versions[cmd.commandClass as Integer] + def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass) + def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data) + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract CRC16 command from $cmd" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + log.info "zwaveEvent SensorMultilevelReport called, ${cmd}" + def map = [:] + def result = [] + switch (cmd.sensorType) { + case 1: + map.name = "temperature" + def cmdScale = cmd.scale == 1 ? "F" : "C" + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) + map.unit = getTemperatureScale() + break + case 5: + map.name = "humidity" + map.value = cmd.scaledSensorValue.toInteger() + map.unit = "%" + break + default: + map.descriptionText = cmd.toString() + } + log.debug "SensorMultilevelReport, ${map}, ${map.name}, ${map.value}, ${map.unit}" + result << createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.Command cmd, endpoint = null) { + log.info "zwaveEvent ***** Unhandled Command called, cmd '${cmd}', endpoint '${endpoint}' *****" + [descriptionText: "Unhandled $device.displayName: $cmd", isStateChange: true] +} + + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping(endpoint = null) { + log.info "ping called: endpoint '${endpoint}' state '${state}'" + log.debug "ping : device.currentValue : " + device.currentValue("DeviceWatch-DeviceStatus") + if(endpoint) { + refresh(endpoint) + } else { + refresh() + } +} + +def refresh(endpoint = null) { + log.info "refresh called: endpint '${endpoint}' " + if(endpoint) { + secureEncap(zwave.basicV1.basicGet(), endpoint) + } else { + def commands = [] + commands << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1) + commands << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 5) + sendCommands(commands,1000) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd){ + log.info "zwaveEvent ConfigurationReport called: ${cmd}" + switch (cmd.parameterNumber) { + case 1: + state.reportingInterval = cmd.scaledConfigurationValue + break + /* + case 2: + state.tempOffset = cmd.scaledConfigurationValue + break + case 3: + state.humidityOffset = cmd.scaledConfigurationValue + break + */ + } + //log.debug "zwaveEvent ConfigurationReport: reportingInterval '${state.reportingInterval}', tempOffset '${state.tempOffset}', humidityOffset '${state.humidityOffset}%'" +} + +def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelEndPointReport cmd, endpoint = null) { + log.info "zwaveEvent MultiChannelEndPointReport called: cmd '${cmd}'" + if(!childDevices) { + def numberOfChild = getNumberOfChildFromModel() + log.debug "MultiChannelEndPointReport: numberOfChild '${numberOfChild}'" + if (numberOfChild) { + addChildSwitches(numberOfChild) + } else { + log.debug "child endpoint=$cmd.endPoints" + addChildSwitches(cmd.endPoints) + } + } +} + +def childOn(deviceNetworkId) { + log.info "childOn called: deviceNetworkId '${deviceNetworkId}'" + def switchId = getSwitchId(deviceNetworkId) + if (switchId != null) sendHubCommand onOffCmd(0xFF, switchId) +} + +def childOff(deviceNetworkId) { + log.info "childOff called: deviceNetworkId '${deviceNetworkId}'" + def switchId = getSwitchId(deviceNetworkId) + if (switchId != null) sendHubCommand onOffCmd(0x00, switchId) +} + +private sendCommands(cmds, delay=1000) { + log.info "sendCommands called: cmds '${cmds}', delay '${delay}'" + sendHubCommand(cmds, delay) +} + +private secureEncap(cmd, endpoint = null) { + log.info "secureEncap called" + + def cmdEncap = [] + if (endpoint) { + cmdEncap = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd) + } else { + cmdEncap = cmd + } + + if (zwaveInfo?.zw?.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmdEncap).format() + } else if (zwaveInfo?.cc?.contains("56")){ + zwave.crc16EncapV1.crc16Encap().encapsulate(cmdEncap).format() + } else { + cmdEncap.format() + } + +} + +private changeSwitch(endpoint, value) { + log.info "changeSwitch called: value: '${value}', endpoint: '${endpoint}'" + def result = [] + if(endpoint) { + String childDni = "${device.deviceNetworkId}:$endpoint" + def child = childDevices.find { it.deviceNetworkId == childDni } + log.debug "changeSwitch: endpoint '${endpoint}', value: '${value}')" + result << child.sendEvent(name: "switch", value: value) + log.debug "changeSwitch: result '${result}'" + } + result +} + +private getNumberOfChildFromModel() { + if ((zwaveInfo.prod.equals("0063")) || (zwaveInfo.prod.equals("0066"))) { + return 3 + } else if ((zwaveInfo.prod.equals("0062")) || (zwaveInfo.prod.equals("0065"))) { + return 2 + } else if ((zwaveInfo.prod.equals("0061")) || (zwaveInfo.prod.equals("0064"))) { + return 1 + } else { + return 0 + } + return 0 +} + +private onOffCmd(value, endpoint) { + log.info "onOffCmd called: val:${value}, ep:${endpoint}" + secureEncap(zwave.basicV1.basicSet(value: value), endpoint) +} + +private getSwitchId(deviceNetworkId) { + log.info "getSwitchId called: ${deviceNetworkId}" + def split = deviceNetworkId?.split(":") + return (split.length > 1) ? split[1] as Integer : null +} + +private addChildSwitches(numberOfSwitches) { + log.info "addChildSwitches called: numberOfSwitches '${numberOfSwitches}'" + for(def endpoint : 1..numberOfSwitches) { + try { + String childDni = "${device.deviceNetworkId}:$endpoint" + def componentLabel = "Dawon Smart Switch${endpoint}" + def child = addChildDevice("Child Switch", childDni, device.hubId, + [completedSetup: true, label: componentLabel, isComponent: false]) + childOff(childDni) + } catch(Exception e) { + log.warn "addChildSwitches Exception: ${e}" + } + } +} diff --git a/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy b/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy index 9ad9616961f..cdbcb998107 100644 --- a/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy +++ b/devicetypes/smartthings/dimmer-switch.src/dimmer-switch.groovy @@ -22,9 +22,9 @@ metadata { capability "Health Check" capability "Light" - fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall Smart Dimmer" - fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE In-Wall Smart Dimmer" - fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Plug-In Smart Dimmer" + fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE Dimmer Switch" //GE In-Wall Smart Dimmer + fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE Dimmer Switch" //GE In-Wall Smart Dimmer + fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Dimmer Switch" //GE Plug-In Smart Dimmer } simulator { diff --git a/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy b/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy index 95afcea1a98..60dfb29cfe2 100644 --- a/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy +++ b/devicetypes/smartthings/eaton-5-scene-keypad.src/eaton-5-scene-keypad.groovy @@ -20,7 +20,7 @@ metadata { capability "Switch" //zw:L type:0202 mfr:001A prod:574D model:0000 ver:2.05 zwv:2.78 lib:01 cc:87,77,86,22,2D,85,72,21,70 - fingerprint mfr: "001A", prod: "574D", model: "0000", deviceJoinName: "Eaton 5-Scene Keypad" + fingerprint mfr: "001A", prod: "574D", model: "0000", deviceJoinName: "Eaton Switch" //Eaton 5-Scene Keypad } tiles(scale: 2) { diff --git a/devicetypes/smartthings/eaton-accessory-dimmer.src/eaton-accessory-dimmer.groovy b/devicetypes/smartthings/eaton-accessory-dimmer.src/eaton-accessory-dimmer.groovy index ed2aa4bc1f9..deac3e1c31a 100644 --- a/devicetypes/smartthings/eaton-accessory-dimmer.src/eaton-accessory-dimmer.groovy +++ b/devicetypes/smartthings/eaton-accessory-dimmer.src/eaton-accessory-dimmer.groovy @@ -22,7 +22,7 @@ metadata { capability "Sensor" capability "Light" - fingerprint mfr: "001A", prod: "4441", model: "0000", deviceJoinName: "Eaton RF Accessory Dimmer" + fingerprint mfr: "001A", prod: "4441", model: "0000", deviceJoinName: "Eaton Dimmer Switch" //Eaton RF Accessory Dimmer } simulator { diff --git a/devicetypes/smartthings/eaton-anyplace-switch.src/eaton-anyplace-switch.groovy b/devicetypes/smartthings/eaton-anyplace-switch.src/eaton-anyplace-switch.groovy index 696f571b521..b73974a46bb 100644 --- a/devicetypes/smartthings/eaton-anyplace-switch.src/eaton-anyplace-switch.groovy +++ b/devicetypes/smartthings/eaton-anyplace-switch.src/eaton-anyplace-switch.groovy @@ -19,7 +19,7 @@ metadata { capability "Switch" //zw:S type:0100 mfr:001A prod:4243 model:0000 ver:3.01 zwv:3.67 lib:01 cc:72,77,86,85 ccOut:26 - fingerprint mfr: "001A", prod: "4243", model: "0000", deviceJoinName: "Eaton Anyplace Switch" + fingerprint mfr: "001A", prod: "4243", model: "0000", deviceJoinName: "Eaton Switch" //Eaton Anyplace Switch } tiles { diff --git a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy index 7e83727452b..a121f454438 100644 --- a/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy +++ b/devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy @@ -26,6 +26,12 @@ metadata { capability "Relative Humidity Measurement" capability "Health Check" + // New discrete thermostat capabilities, added to replace "Thermostat" and prepare for migration to st-schema + capability "Thermostat Cooling Setpoint" + capability "Thermostat Heating Setpoint" + capability "Thermostat Mode" + capability "Thermostat Fan Mode" + command "generateEvent" command "resumeProgram" command "switchMode" diff --git a/devicetypes/smartthings/ecolink-water-freeze-sensor.src/ecolink-water-freeze-sensor.groovy b/devicetypes/smartthings/ecolink-water-freeze-sensor.src/ecolink-water-freeze-sensor.groovy index 8de3aa50f3b..e04be834075 100644 --- a/devicetypes/smartthings/ecolink-water-freeze-sensor.src/ecolink-water-freeze-sensor.groovy +++ b/devicetypes/smartthings/ecolink-water-freeze-sensor.src/ecolink-water-freeze-sensor.groovy @@ -22,7 +22,7 @@ metadata { capability "Battery" capability "Health Check" - fingerprint mfr: "014A", prod: "0005", model: "0010", deviceJoinName: "Ecolink Water/Freeze Sensor" + fingerprint mfr: "014A", prod: "0005", model: "0010", deviceJoinName: "Ecolink Water Leak Sensor" //Ecolink Water/Freeze Sensor } simulator { diff --git a/devicetypes/smartthings/ecolink-wireless-siren.src/ecolink-wireless-siren.groovy b/devicetypes/smartthings/ecolink-wireless-siren.src/ecolink-wireless-siren.groovy index 9ab82b84f5c..b0b87394ee5 100644 --- a/devicetypes/smartthings/ecolink-wireless-siren.src/ecolink-wireless-siren.groovy +++ b/devicetypes/smartthings/ecolink-wireless-siren.src/ecolink-wireless-siren.groovy @@ -23,7 +23,7 @@ metadata { capability "Alarm" //zw:L type:1005 mfr:014A prod:0005 model:000A ver:1.10 zwv:4.05 lib:03 cc:5E,86,72,5A,85,59,73,25,60,8E,20,7A role:05 ff:8F00 ui:8F00 epc:4 ep:['1005 20,25,5E,59,85'] - fingerprint mfr: "014A", prod: "0005", model: "000A", deviceJoinName: "Ecolink Wireless Siren" + fingerprint mfr: "014A", prod: "0005", model: "000A", deviceJoinName: "Ecolink Siren" //Ecolink Wireless Siren } tiles { @@ -96,6 +96,14 @@ def createEvents(value) { } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand() def srcEndpoint = cmd.sourceEndPoint def destEnd = cmd.destinationEndPoint diff --git a/devicetypes/smartthings/ecolink-zigbee-water-freeze-sensor.src/ecolink-zigbee-water-freeze-sensor.groovy b/devicetypes/smartthings/ecolink-zigbee-water-freeze-sensor.src/ecolink-zigbee-water-freeze-sensor.groovy index 4eae213ad23..0c07ee5bfa4 100644 --- a/devicetypes/smartthings/ecolink-zigbee-water-freeze-sensor.src/ecolink-zigbee-water-freeze-sensor.groovy +++ b/devicetypes/smartthings/ecolink-zigbee-water-freeze-sensor.src/ecolink-zigbee-water-freeze-sensor.groovy @@ -28,7 +28,7 @@ metadata { capability "Temperature Measurement" capability "Temperature Alarm" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0020,0402,0500,0B05,FC01,FC02", outClusters: "0019", manufacturer: "Ecolink", model: "FLZB1-ECO", deviceJoinName: "Ecolink Water/Freeze Sensor" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0020,0402,0500,0B05,FC01,FC02", outClusters: "0019", manufacturer: "Ecolink", model: "FLZB1-ECO", deviceJoinName: "Ecolink Water Leak Sensor" //Ecolink Water/Freeze Sensor } tiles(scale: 2) { @@ -90,7 +90,7 @@ def parse(String description) { } else if (map.name == "temperature") { freezeStatus(map.value) if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? "${device.displayName} was ${map.value}°C" : "${device.displayName} was ${map.value}°F" map.translatable = true diff --git a/devicetypes/smartthings/econet-vent.src/econet-vent.groovy b/devicetypes/smartthings/econet-vent.src/econet-vent.groovy index 9dc3c5b5db9..8b3b6ccf085 100644 --- a/devicetypes/smartthings/econet-vent.src/econet-vent.groovy +++ b/devicetypes/smartthings/econet-vent.src/econet-vent.groovy @@ -31,8 +31,8 @@ metadata { command "open" command "close" - fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20" - fingerprint mfr:"0157", prod:"0100", model:"0100", deviceJoinName: "EcoNet Controls Z-Wave Vent" + fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20", deviceJoinName: "EcoNet Vent" + fingerprint mfr:"0157", prod:"0100", model:"0100", deviceJoinName: "EcoNet Vent" //EcoNet Controls Z-Wave Vent } simulator { diff --git a/devicetypes/smartthings/ecosmart-4button-remote.src/ecosmart-4button-remote.groovy b/devicetypes/smartthings/ecosmart-4button-remote.src/ecosmart-4button-remote.groovy new file mode 100644 index 00000000000..6e92d82f250 --- /dev/null +++ b/devicetypes/smartthings/ecosmart-4button-remote.src/ecosmart-4button-remote.groovy @@ -0,0 +1,215 @@ +/* + * Copyright 2020 SmartThings + * + * 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. + */ + +import groovy.json.JsonOutput +import physicalgraph.zigbee.zcl.DataType + +metadata { + definition (name: "EcoSmart 4-button Remote", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.remotecontroller", mcdSync: true, runLocally: false, executeCommandsLocally: false, mnmn: "SmartThings", vid: "generic-4-button") { + capability "Actuator" + capability "Battery" + capability "Button" + capability "Holdable Button" + capability "Configuration" + capability "Sensor" + capability "Health Check" + + fingerprint inClusters: "0000, 0001, 0003, 1000, FD01", outClusters: "0003, 0004, 0006, 0008, 0019, 0300, 1000", manufacturer: "LDS", model: "ZBT-CCTSwitch-D0001", deviceJoinName: "EcoSmart Remote Control" //EcoSmart 4-button remote + } + + tiles { + standardTile("button", "device.button", width: 2, height: 2) { + state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff" + state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC" + } + + valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false) { + state "battery", label:'${currentValue}% battery', unit:"" + } + + main (["button"]) + details(["button", "battery"]) + } +} + +private getCLUSTER_GROUPS() { 0x0004 } + +private channelNumber(String dni) { + dni.split(":")[-1] as Integer +} + +private getButtonName(buttonNum) { + return "${device.displayName} " + "Button ${buttonNum}" +} + +private void createChildButtonDevices(numberOfButtons) { + state.oldLabel = device.label + + def existingChildren = getChildDevices() + + log.debug "Creating $numberOfButtons children" + + for (i in 1..numberOfButtons) { + def newChildNetworkId = "${device.deviceNetworkId}:${i}" + def childExists = (existingChildren.find {child -> child.getDeviceNetworkId() == newChildNetworkId} != NULL) + + if (!childExists) { + log.debug "Creating child $i" + def child = addChildDevice("Child Button", newChildNetworkId, device.hubId, + [completedSetup: true, label: getButtonName(i), + isComponent: true, componentName: "button$i", componentLabel: "Button ${i}"]) + + child.sendEvent(name: "supportedButtonValues", value: ["pushed"].encodeAsJSON(), displayed: false) + child.sendEvent(name: "numberOfButtons", value: 1, displayed: false) + child.sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], displayed: false) + } else { + log.debug "Child $i already exists, not creating" + } + } +} + +def installed() { + def numberOfButtons = 4 + state.ignoreNextButton3 = false + + createChildButtonDevices(numberOfButtons) + + sendEvent(name: "supportedButtonValues", value: ["pushed"].encodeAsJSON(), displayed: false) + sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false) + numberOfButtons.times { + sendEvent(name: "button", value: "pushed", data: [buttonNumber: it+1], displayed: false) + } + + // These devices don't report regularly so they should only go OFFLINE when Hub is OFFLINE + sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false) +} + +def updated() { + if (childDevices && device.label != state.oldLabel) { + childDevices.each { + def newLabel = getButtonName(channelNumber(it.deviceNetworkId)) + it.setLabel(newLabel) + } + state.oldLabel = device.label + } +} + +def configure() { + log.debug "Configuring device ${device.getDataValue("model")}" + + def cmds = zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21, DataType.UINT8, 30, 21600, 0x01) + + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21) + + zigbee.addBinding(zigbee.ONOFF_CLUSTER) + + // This device doesn't report a binding to this group but will send all messages to this group ID + addHubToGroup(0x4003) + + + cmds +} + +def parse(String description) { + log.debug "Parsing message from device: '$description'" + def event = zigbee.getEvent(description) + if (event) { + log.debug "Creating event: ${event}" + sendEvent(event) + } else { + if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) { + def descMap = zigbee.parseDescriptionAsMap(description) + if (descMap.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.attrInt == 0x0021) { + event = getBatteryEvent(zigbee.convertHexToInt(descMap.value)) + } else if (descMap.clusterInt == zigbee.ONOFF_CLUSTER || + descMap.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER || + descMap.clusterInt == zigbee.COLOR_CONTROL_CLUSTER) { + event = getButtonEvent(descMap) + } + } + + def result = [] + if (event) { + log.debug "Creating event: ${event}" + result = createEvent(event) + } + + return result + } +} + +private Map getBatteryEvent(value) { + def result = [:] + result.value = value / 2 + result.name = 'battery' + result.descriptionText = "${device.displayName} battery was ${result.value}%" + return result +} + +private sendButtonEvent(buttonNumber, buttonState) { + def child = childDevices?.find { channelNumber(it.deviceNetworkId) == buttonNumber } + + if (child) { + def descriptionText = "$child.displayName was $buttonState" // TODO: Verify if this is needed, and if capability template already has it handled + + child?.sendEvent([name: "button", value: buttonState, data: [buttonNumber: 1], descriptionText: descriptionText, isStateChange: true]) + } else { + log.debug "Child device $buttonNumber not found!" + } +} + +private Map getButtonEvent(Map descMap) { + def buttonState = "" + def buttonNumber = 0 + Map result = [:] + + // Button 1 + if (descMap.clusterInt == zigbee.ONOFF_CLUSTER) { + buttonNumber = 1 + + // Button 2 + } else if (descMap.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER && + (descMap.commandInt == 0x00 || descMap.commandInt == 0x01)) { + buttonNumber = 2 + + // Button 3 + } else if (descMap.clusterInt == zigbee.COLOR_CONTROL_CLUSTER) { + if (descMap.commandInt == 0x0A || (descMap.commandInt == 0x4B && descMap.data[0] != "00")) { + if (state.ignoreNextButton3) { + // button 4 sends 2 cmds; one is a button 3 cmd. We want to ignore these specific cmds + state.ignoreNextButton3 = false + } else { + buttonNumber = 3 + } + } + + // Button 4 + } else if (descMap.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER && + descMap.commandInt == 0x04) { + // remember to ignore the next button 3 message we get + state.ignoreNextButton3 = true + buttonNumber = 4 + } + + + if (buttonNumber != 0) { + // Create and send component event + sendButtonEvent(buttonNumber, "pushed") + } + result +} + +private List addHubToGroup(Integer groupAddr) { + ["st cmd 0x0000 0x01 ${CLUSTER_GROUPS} 0x00 {${zigbee.swapEndianHex(zigbee.convertToHexString(groupAddr,4))} 00}", + "delay 200"] +} \ No newline at end of file diff --git a/devicetypes/smartthings/everspring-flood-sensor.src/everspring-flood-sensor.groovy b/devicetypes/smartthings/everspring-flood-sensor.src/everspring-flood-sensor.groovy index 94919c0a63d..c2d4aea848a 100644 --- a/devicetypes/smartthings/everspring-flood-sensor.src/everspring-flood-sensor.groovy +++ b/devicetypes/smartthings/everspring-flood-sensor.src/everspring-flood-sensor.groovy @@ -19,7 +19,7 @@ metadata { capability "Battery" capability "Health Check" - fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71" + fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71", deviceJoinName: "Everspring Water Leak Sensor" } simulator { diff --git a/devicetypes/smartthings/everspring-illuminance-sensor.src/everspring-illuminance-sensor.groovy b/devicetypes/smartthings/everspring-illuminance-sensor.src/everspring-illuminance-sensor.groovy index 6a202f862cc..1cf343aa8a2 100644 --- a/devicetypes/smartthings/everspring-illuminance-sensor.src/everspring-illuminance-sensor.groovy +++ b/devicetypes/smartthings/everspring-illuminance-sensor.src/everspring-illuminance-sensor.groovy @@ -24,7 +24,7 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint mfr:"0060", prod:"0007", model:"0001" + fingerprint mfr:"0060", prod:"0007", model:"0001", deviceJoinName: "Everspring Illuminance Sensor" } simulator { diff --git a/devicetypes/smartthings/everspring-st814.src/everspring-st814.groovy b/devicetypes/smartthings/everspring-st814.src/everspring-st814.groovy index 47b24487203..ee172821ddc 100644 --- a/devicetypes/smartthings/everspring-st814.src/everspring-st814.groovy +++ b/devicetypes/smartthings/everspring-st814.src/everspring-st814.groovy @@ -25,7 +25,7 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint mfr:"0060", prod:"0006", model:"0001" + fingerprint mfr:"0060", prod:"0006", model:"0001", deviceJoinName: "Everspring Multipurpose Sensor" } simulator { @@ -156,6 +156,14 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { def result = null + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2]) log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}") if (encapsulatedCommand) { diff --git a/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy b/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy index ff59487d68b..7ed24482a84 100755 --- a/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy +++ b/devicetypes/smartthings/ezex-smart-electric-switch.src/ezex-smart-electric-switch.groovy @@ -22,7 +22,7 @@ metadata { capability "Sensor" capability "Configuration" - fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0006, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR116Z-HA", deviceJoinName: "Smart Electric Switch" + fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0006, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR116Z-HA", deviceJoinName: "eZEX Switch" //Smart Electric Switch } tiles(scale: 2){ diff --git a/devicetypes/smartthings/ezex-smart-electric-switch.src/i18n/messages.properties b/devicetypes/smartthings/ezex-smart-electric-switch.src/i18n/messages.properties index 3557b348a9e..da99a7645fc 100755 --- a/devicetypes/smartthings/ezex-smart-electric-switch.src/i18n/messages.properties +++ b/devicetypes/smartthings/ezex-smart-electric-switch.src/i18n/messages.properties @@ -13,5 +13,6 @@ # under the License. # Korean (ko) # Device Preferences +'''eZEX Switch'''.ko=스마트 전자식 스위치 '''Smart Electric Switch'''.ko=스마트 전자식 스위치 #============================================================================== diff --git a/devicetypes/smartthings/ezex-temp-humidity-sensor.src/ezex-temp-humidity-sensor.groovy b/devicetypes/smartthings/ezex-temp-humidity-sensor.src/ezex-temp-humidity-sensor.groovy index c0ee4395d24..6a1be540d2c 100755 --- a/devicetypes/smartthings/ezex-temp-humidity-sensor.src/ezex-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/ezex-temp-humidity-sensor.src/ezex-temp-humidity-sensor.groovy @@ -23,13 +23,13 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000,0003,0402,0405,0500", outClusters: "0019", model: "E282-KR0B0Z1-HA", deviceJoinName: "Smart Temperature/Humidity Sensor (AC Type)" + fingerprint profileId: "0104", inClusters: "0000,0003,0402,0405,0500", outClusters: "0019", model: "E282-KR0B0Z1-HA", deviceJoinName: "eZEX Multipurpose Sensor" //Smart Temperature/Humidity Sensor (AC Type) } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false - input "humidityOffset", "number", title: "Humidity Offset", description: "Adjust humidity by this percentage", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false + input "humidityOffset", "number", title: "Humidity offset", description: "Enter a percentage to adjust the humidity.", range: "*..*", displayDuringSetup: false } tiles(scale: 2) { @@ -76,7 +76,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F' map.translatable = true diff --git a/devicetypes/smartthings/ezex-temp-humidity-sensor.src/i18n/messages.properties b/devicetypes/smartthings/ezex-temp-humidity-sensor.src/i18n/messages.properties index 59087b6cbc7..df90df538c9 100755 --- a/devicetypes/smartthings/ezex-temp-humidity-sensor.src/i18n/messages.properties +++ b/devicetypes/smartthings/ezex-temp-humidity-sensor.src/i18n/messages.properties @@ -13,5 +13,199 @@ # under the License. # Korean (ko) # Device Preferences +'''eZEX Multipurpose Sensor'''.ko=스마트 온도/습도센서 '''Smart Temperature/Humidity Sensor (AC Type)'''.ko=스마트 온도/습도센서 #============================================================================== +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +'''Enter a percentage to adjust the humidity.'''.en=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-gb=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-us=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-ca=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.sq=Fut një përqindje për të përshtatur lagështinë. +'''Enter a percentage to adjust the humidity.'''.ar=أدخل نسبة مئوية لتعديل الرطوبة. +'''Enter a percentage to adjust the humidity.'''.be=Увядзіце працэнт, каб адрэгуляваць вільготнасць. +'''Enter a percentage to adjust the humidity.'''.sr-ba=Unesite procenat da prilagodite vlažnost. +'''Enter a percentage to adjust the humidity.'''.bg=Въведете процент, за да регулирате влажността. +'''Enter a percentage to adjust the humidity.'''.ca=Introdueix un percentatge per ajustar la humitat. +'''Enter a percentage to adjust the humidity.'''.zh-cn=请输入百分比来调整湿度。 +'''Enter a percentage to adjust the humidity.'''.zh-hk=輸入百分比以調整濕度。 +'''Enter a percentage to adjust the humidity.'''.zh-tw=請輸入百分比來調整濕度。 +'''Enter a percentage to adjust the humidity.'''.hr=Unesite postotak za promjenu vlažnosti. +'''Enter a percentage to adjust the humidity.'''.cs=Upravte vlhkost zadáním procenta. +'''Enter a percentage to adjust the humidity.'''.da=Angiv en procentsats for at justere fugtigheden. +'''Enter a percentage to adjust the humidity.'''.nl=Voer een percentage in om de vochtigheid aan te passen. +'''Enter a percentage to adjust the humidity.'''.et=Sisestage protsent, et muuta niiskust. +'''Enter a percentage to adjust the humidity.'''.fi=Anna prosentti kosteuden säätämistä varten. +'''Enter a percentage to adjust the humidity.'''.fr=Entrez un pourcentage pour ajuster l'humidité. +'''Enter a percentage to adjust the humidity.'''.de=Geben Sie einen Prozentsatz ein, um die Feuchtigkeit anzupassen. +'''Enter a percentage to adjust the humidity.'''.el=Εισαγάγετε ποσοστό για την προσαρμογή της υγρασίας. +'''Enter a percentage to adjust the humidity.'''.iw=כדי להתאים רמת לחות, הזן אחוז. +'''Enter a percentage to adjust the humidity.'''.hi-in=नमी समायोजित करने के लिए, प्रतिशत प्रविष्ट करें। +'''Enter a percentage to adjust the humidity.'''.hu=A páratartalom beállításához adjon meg egy százalékos értéket. +'''Enter a percentage to adjust the humidity.'''.is=Sláðu inn prósentu til að stilla rakastigið. +'''Enter a percentage to adjust the humidity.'''.in=Masukkan persentase untuk mengatur kelembapan. +'''Enter a percentage to adjust the humidity.'''.it=Inserite una percentuale per regolare l'umidità. +'''Enter a percentage to adjust the humidity.'''.ja=湿度を調整するパーセンテージを入力してください。 +'''Enter a percentage to adjust the humidity.'''.ko=원하는 습도율을 입력하고 실내 습도를 설정해 보세요. +'''Enter a percentage to adjust the humidity.'''.lv=Ievadiet procentuālo daudzumu, lai pielāgotu mitruma līmeni. +'''Enter a percentage to adjust the humidity.'''.lt=Įveskite procentus ir sureguliuokite drėgnumą. +'''Enter a percentage to adjust the humidity.'''.ms=Masukkan peratusan untuk melaraskan kelembapan. +'''Enter a percentage to adjust the humidity.'''.no=Angi en prosent for å justere fuktigheten. +'''Enter a percentage to adjust the humidity.'''.pl=Wprowadź procent, aby ustawić wilgotność. +'''Enter a percentage to adjust the humidity.'''.pt=Introduzir uma percentagem para ajustar a humidade. +'''Enter a percentage to adjust the humidity.'''.ro=Introduceți un procent pentru ajustarea umidității. +'''Enter a percentage to adjust the humidity.'''.ru=Введите процент для регулировки влажности. +'''Enter a percentage to adjust the humidity.'''.sr=Unesite procenat da biste prilagodili vlažnost. +'''Enter a percentage to adjust the humidity.'''.sk=Upravte vlhkosť zadaním percenta. +'''Enter a percentage to adjust the humidity.'''.sl=Vnesite odstotek, da prilagodite vlažnost. +'''Enter a percentage to adjust the humidity.'''.es=Introduce un porcentaje para ajustar la humedad. +'''Enter a percentage to adjust the humidity.'''.sv=Ange ett procenttal när du vill justera fuktigheten. +'''Enter a percentage to adjust the humidity.'''.th=ใส่เปอร์เซ็นต์เพื่อปรับความชื้น +'''Enter a percentage to adjust the humidity.'''.tr=Nemi ayarlamak için bir yüzde değeri girin. +'''Enter a percentage to adjust the humidity.'''.uk=Уведіть відсоток для регулювання вологості. +'''Enter a percentage to adjust the humidity.'''.vi=Nhập phần trăm để hiệu chỉnh độ ẩm. +'''Humidity offset'''.en=Humidity offset +'''Humidity offset'''.en-gb=Humidity offset +'''Humidity offset'''.en-us=Humidity offset +'''Humidity offset'''.en-ca=Humidity offset +'''Humidity offset'''.sq=Shmangia në lagështi +'''Humidity offset'''.ar=تعويض الرطوبة +'''Humidity offset'''.be=Карэкцыя вільготнасці +'''Humidity offset'''.sr-ba=Kompenzacija vlage +'''Humidity offset'''.bg=Компенсация на влажността +'''Humidity offset'''.ca=Compensació d'humitat +'''Humidity offset'''.zh-cn=湿度偏差 +'''Humidity offset'''.zh-hk=濕度偏差 +'''Humidity offset'''.zh-tw=濕度偏差 +'''Humidity offset'''.hr=Kompenzacija vlage +'''Humidity offset'''.cs=Posun vlhkosti +'''Humidity offset'''.da=Fugtighedsforskydning +'''Humidity offset'''.nl=Vochtigheidsverschil +'''Humidity offset'''.et=Niiskuse nihkeväärtus +'''Humidity offset'''.fi=Ilmankosteuden siirtymä +'''Humidity offset'''.fr=Compensation de l'humidité +'''Humidity offset'''.fr-ca=Compensation de l'humidité +'''Humidity offset'''.de=Luftfeuchtigkeitsabweichung +'''Humidity offset'''.el=Αντιστάθμιση υγρασίας +'''Humidity offset'''.iw=קיזוז לחות +'''Humidity offset'''.hi-in=नमी की भरपाई +'''Humidity offset'''.hu=Páratartalom-érték eltolása +'''Humidity offset'''.is=Vikmörk raka +'''Humidity offset'''.in=Offset kelembapan +'''Humidity offset'''.it=Differenza umidità +'''Humidity offset'''.ja=湿度オフセット +'''Humidity offset'''.ko=습도 오프셋 +'''Humidity offset'''.lv=Mitruma nobīde +'''Humidity offset'''.lt=Drėgnumo skirtumas +'''Humidity offset'''.ms=Ofset kelembapan +'''Humidity offset'''.no=Fuktighetsforskyvning +'''Humidity offset'''.pl=Różnica wilgotności +'''Humidity offset'''.pt=Diferença de humidade +'''Humidity offset'''.ro=Decalaj umiditate +'''Humidity offset'''.ru=Поправка влажности +'''Humidity offset'''.sr=Odstupanje vlažnosti +'''Humidity offset'''.sk=Posun vlhkosti +'''Humidity offset'''.sl=Odmik vlažnosti +'''Humidity offset'''.es=Compensación de humedad +'''Humidity offset'''.sv=Luftfuktighetsavvikelse +'''Humidity offset'''.th=การชดเชยความชื้น +'''Humidity offset'''.tr=Nem ofseti +'''Humidity offset'''.uk=Поправка вологості +'''Humidity offset'''.vi=Độ lệch độ ẩm +# End of Device Preferences diff --git a/devicetypes/smartthings/fibaro-dimmer.src/fibaro-dimmer.groovy b/devicetypes/smartthings/fibaro-dimmer.src/fibaro-dimmer.groovy index 068e4912fc8..2e594f93854 100644 --- a/devicetypes/smartthings/fibaro-dimmer.src/fibaro-dimmer.groovy +++ b/devicetypes/smartthings/fibaro-dimmer.src/fibaro-dimmer.groovy @@ -33,7 +33,7 @@ metadata { command "listCurrentParams" command "updateZwaveParam" - fingerprint deviceId: "0x1101", inClusters: "0x72,0x86,0x70,0x85,0x8E,0x26,0x7A,0x27,0x73,0xEF,0x26,0x2B" + fingerprint deviceId: "0x1101", inClusters: "0x72,0x86,0x70,0x85,0x8E,0x26,0x7A,0x27,0x73,0xEF,0x26,0x2B", deviceJoinName: "Fibaro Dimmer Switch" } simulator { diff --git a/devicetypes/smartthings/fibaro-door-window-sensor.src/fibaro-door-window-sensor.groovy b/devicetypes/smartthings/fibaro-door-window-sensor.src/fibaro-door-window-sensor.groovy index 24d21f763e9..0a776eb647e 100644 --- a/devicetypes/smartthings/fibaro-door-window-sensor.src/fibaro-door-window-sensor.groovy +++ b/devicetypes/smartthings/fibaro-door-window-sensor.src/fibaro-door-window-sensor.groovy @@ -47,7 +47,7 @@ command "updateZwaveParam" command "test" - fingerprint deviceId: "0x2001", inClusters: "0x30,0x9C,0x85,0x72,0x70,0x86,0x80,0x56,0x84,0x7A,0xEF,0x2B" + fingerprint deviceId: "0x2001", inClusters: "0x30,0x9C,0x85,0x72,0x70,0x86,0x80,0x56,0x84,0x7A,0xEF,0x2B", deviceJoinName: "Fibaro Open/Closed Sensor" } simulator { @@ -96,8 +96,8 @@ } //this will display a temperature tile for the DS18B20 sensor - //main(["contact", "temperature"]) //COMMENT ME OUT IF NO TEMP INSTALLED - //details(["contact", "temperature", "battery"]) //COMMENT ME OUT IF NO TEMP INSTALLED + //main(["contact", "temperature"])//COMMENT ME OUT IF NO TEMP INSTALLED + //details(["contact", "temperature", "battery"]) //COMMENT ME OUT IF NO TEMP INSTALLED //this will hide the temperature tile if the DS18B20 sensor is not installed main(["contact"]) //UNCOMMENT ME IF NO TEMP INSTALLED @@ -149,6 +149,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 2, 0x31: 2]) // can specify command class versions here like in zwave.parse log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}") if (encapsulatedCommand) { diff --git a/devicetypes/smartthings/fibaro-flood-sensor.src/fibaro-flood-sensor.groovy b/devicetypes/smartthings/fibaro-flood-sensor.src/fibaro-flood-sensor.groovy index 1bf475941bc..48a3dc5996a 100644 --- a/devicetypes/smartthings/fibaro-flood-sensor.src/fibaro-flood-sensor.groovy +++ b/devicetypes/smartthings/fibaro-flood-sensor.src/fibaro-flood-sensor.groovy @@ -47,10 +47,10 @@ metadata { command "updateZwaveParam" command "test" - fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84" - fingerprint mfr:"010F", prod:"0000", model:"2002" - fingerprint mfr:"010F", prod:"0000", model:"1002" - fingerprint mfr:"010F", prod:"0B00", model:"1001" + fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84", deviceJoinName: "Fibaro Water Leak Sensor" + fingerprint mfr:"010F", prod:"0000", model:"2002", deviceJoinName: "Fibaro Water Leak Sensor" + fingerprint mfr:"010F", prod:"0000", model:"1002", deviceJoinName: "Fibaro Water Leak Sensor" + fingerprint mfr:"010F", prod:"0B00", model:"1001", deviceJoinName: "Fibaro Water Leak Sensor" } simulator { @@ -128,6 +128,14 @@ def parse(String description) def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 2, 0x31: 2]) // can specify command class versions here like in zwave.parse log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}") if (encapsulatedCommand) { diff --git a/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy b/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy index c98ac8afec2..c535e6ab08d 100644 --- a/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy +++ b/devicetypes/smartthings/fibaro-heat-controller.src/fibaro-heat-controller.groovy @@ -26,7 +26,7 @@ metadata { command "setThermostatSetpointDown" command "switchMode" - fingerprint mfr: "010F", prod: "1301", model: "1000", deviceJoinName: "Fibaro Heat Controller" + fingerprint mfr: "010F", prod: "1301", model: "1000", deviceJoinName: "Fibaro Thermostat" //Fibaro Heat Controller } tiles(scale: 2) { @@ -117,6 +117,14 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand() if (encapsulatedCommand) { log.debug "MultiChannel Encapsulation: ${encapsulatedCommand}" @@ -143,7 +151,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd, sourceE result } -def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) { +def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd, sourceEndPoint = null) { def mode switch (cmd.mode) { case 1: @@ -160,14 +168,17 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeRepor createEvent(name: "thermostatMode", value: mode, data: [supportedThermostatModes: state.supportedModes]) } -def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { +def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd, sourceEndPoint = null) { createEvent(name: "heatingSetpoint", value: convertTemperatureIfNeeded(cmd.scaledValue, 'C', cmd.precision), unit: temperatureScale) } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd, sourceEndPoint = null) { def map = [name: "temperature", value: convertTemperatureIfNeeded(cmd.scaledSensorValue, 'C', cmd.precision), unit: temperatureScale] if (map.value != "-100.0") { - sendEventToChild(map) + if (state.isTemperatureReportAbleToChangeStatus) { + changeTemperatureSensorStatus("online") + sendEventToChild(map) + } createEvent(map) } else { changeTemperatureSensorStatus("offline") @@ -179,18 +190,23 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport if (cmd.parameterNumber == 3) { if (cmd.scaledConfigurationValue == 1) { if (!childDevices) { - state.isChildOnline = true addChild() } else { - changeTemperatureSensorStatus("online") refreshChild() } + state.isTemperatureReportAbleToChangeStatus = true + changeTemperatureSensorStatus("online") } else if (cmd.scaledConfigurationValue == 0 && childDevices) { + state.isTemperatureReportAbleToChangeStatus = false changeTemperatureSensorStatus("offline") } } } +def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd, sourceEndPoint = null) { + log.debug "Notification: ${cmd}" +} + def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationBusy cmd) { log.warn "Device is busy, delaying refresh" runIn(15, "forcedRefresh", [overwrite: true]) @@ -282,7 +298,7 @@ private secureEncap(cmd, endpoint = null) { } private secure(cmd) { - if (zwaveInfo.zw.endsWith("s")) { + if (zwaveInfo.zw.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() @@ -317,7 +333,7 @@ def sendEventToChild(event, forced = false) { } def configureChild() { - sendEventToChild(createEvent([name: "checkInterval", value: 6 * 60 * 60 + 36, displayed: false])) + sendEventToChild(createEvent(name: "DeviceWatch-Enroll", value: [protocol: "zwave", scheme:"untracked"].encodeAsJson(), displayed: false), true) } private refreshChild() { diff --git a/devicetypes/smartthings/fibaro-motion-sensor.src/fibaro-motion-sensor.groovy b/devicetypes/smartthings/fibaro-motion-sensor.src/fibaro-motion-sensor.groovy index 248aa5268ee..4025288c30a 100644 --- a/devicetypes/smartthings/fibaro-motion-sensor.src/fibaro-motion-sensor.groovy +++ b/devicetypes/smartthings/fibaro-motion-sensor.src/fibaro-motion-sensor.groovy @@ -54,8 +54,8 @@ command "test" command "configure" - fingerprint mfr:"010F", prod:"0800", model:"2001" - fingerprint mfr:"010F", prod:"0800", model:"1001" + fingerprint mfr:"010F", prod:"0800", model:"2001", deviceJoinName: "Fibaro Motion Sensor" + fingerprint mfr:"010F", prod:"0800", model:"1001", deviceJoinName: "Fibaro Motion Sensor" } simulator { diff --git a/devicetypes/smartthings/fibaro-rgbw-controller.src/fibaro-rgbw-controller.groovy b/devicetypes/smartthings/fibaro-rgbw-controller.src/fibaro-rgbw-controller.groovy index 4f6f592cbff..f8a32e69b29 100644 --- a/devicetypes/smartthings/fibaro-rgbw-controller.src/fibaro-rgbw-controller.groovy +++ b/devicetypes/smartthings/fibaro-rgbw-controller.src/fibaro-rgbw-controller.groovy @@ -1,22 +1,22 @@ /** - * Device Type Definition File + * Device Type Definition File * - * Device Type: Fibaro RGBW Controller - * File Name: fibaro-rgbw-controller.groovy + * Device Type: Fibaro RGBW Controller + * File Name: fibaro-rgbw-controller.groovy * Initial Release: 2015-01-04 * Author: Todd Wackford - * Email: todd@wackford.net + * Email: todd@wackford.net * - * Copyright 2015 SmartThings + * Copyright 2015 SmartThings * - * 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: + * 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 + * 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. + * 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. * */ @@ -31,292 +31,294 @@ capability "Sensor" capability "Configuration" capability "Color Control" - capability "Power Meter" - - command "getDeviceData" - command "softwhite" - command "daylight" - command "warmwhite" - command "red" - command "green" - command "blue" - command "cyan" - command "magenta" - command "orange" - command "purple" - command "yellow" - command "white" - command "fireplace" - command "storm" - command "deepfade" - command "litefade" - command "police" - command "setAdjustedColor" - command "setWhiteLevel" - command "test" - - attribute "whiteLevel", "string" - - fingerprint deviceId: "0x1101", inClusters: "0x27,0x72,0x86,0x26,0x60,0x70,0x32,0x31,0x85,0x33" + capability "Power Meter" + + command "getDeviceData" + command "softwhite" + command "daylight" + command "warmwhite" + command "red" + command "green" + command "blue" + command "cyan" + command "magenta" + command "orange" + command "purple" + command "yellow" + command "white" + command "fireplace" + command "storm" + command "deepfade" + command "litefade" + command "police" + command "setAdjustedColor" + command "setWhiteLevel" + command "test" + + attribute "whiteLevel", "string" + + fingerprint deviceId: "0x1101", inClusters: "0x27,0x72,0x86,0x26,0x60,0x70,0x32,0x31,0x85,0x33", deviceJoinName: "Fibaro Light" } - simulator { - status "on": "command: 2003, payload: FF" - status "off": "command: 2003, payload: 00" - status "09%": "command: 2003, payload: 09" - status "10%": "command: 2003, payload: 0A" - status "33%": "command: 2003, payload: 21" - status "66%": "command: 2003, payload: 42" - status "99%": "command: 2003, payload: 63" - - // reply messages - reply "2001FF,delay 5000,2602": "command: 2603, payload: FF" - reply "200100,delay 5000,2602": "command: 2603, payload: 00" - reply "200119,delay 5000,2602": "command: 2603, payload: 19" - reply "200132,delay 5000,2602": "command: 2603, payload: 32" - reply "20014B,delay 5000,2602": "command: 2603, payload: 4B" - reply "200163,delay 5000,2602": "command: 2603, payload: 63" + simulator { + status "on": "command: 2003, payload: FF" + status "off": "command: 2003, payload: 00" + status "09%": "command: 2003, payload: 09" + status "10%": "command: 2003, payload: 0A" + status "33%": "command: 2003, payload: 21" + status "66%": "command: 2003, payload: 42" + status "99%": "command: 2003, payload: 63" + + // reply messages + reply "2001FF,delay 5000,2602": "command: 2603, payload: FF" + reply "200100,delay 5000,2602": "command: 2603, payload: 00" + reply "200119,delay 5000,2602": "command: 2603, payload: 19" + reply "200132,delay 5000,2602": "command: 2603, payload: 32" + reply "20014B,delay 5000,2602": "command: 2603, payload: 4B" + reply "200163,delay 5000,2602": "command: 2603, payload: 63" } - tiles { + tiles { controlTile("rgbSelector", "device.color", "color", height: 3, width: 3, inactiveLabel: false) { - state "color", action:"setAdjustedColor" + state "color", action:"setAdjustedColor" } controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") { state "level", action:"switch level.setLevel" } controlTile("whiteSliderControl", "device.whiteLevel", "slider", height: 1, width: 3, inactiveLabel: false) { - state "whiteLevel", action:"setWhiteLevel", label:'White Level' - } + state "whiteLevel", action:"setWhiteLevel", label:'White Level' + } standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) { - state "on", label:'${name}', action:"switch.off", icon:"st.illuminance.illuminance.bright", backgroundColor:"#00A0DC", nextState:"turningOff" - state "off", label:'${name}', action:"switch.on", icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff", nextState:"turningOn" - state "turningOn", label:'${name}', icon:"st.illuminance.illuminance.bright", backgroundColor:"#00A0DC" - state "turningOff", label:'${name}', icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff" - } - valueTile("power", "device.power", decoration: "flat") { - state "power", label:'${currentValue} W' - } - standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") { + state "on", label:'${name}', action:"switch.off", icon:"st.illuminance.illuminance.bright", backgroundColor:"#00A0DC", nextState:"turningOff" + state "off", label:'${name}', action:"switch.on", icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff", nextState:"turningOn" + state "turningOn", label:'${name}', icon:"st.illuminance.illuminance.bright", backgroundColor:"#00A0DC" + state "turningOff", label:'${name}', icon:"st.illuminance.illuminance.dark", backgroundColor:"#ffffff" + } + valueTile("power", "device.power", decoration: "flat") { + state "power", label:'${currentValue} W' + } + standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") { state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" } - standardTile("refresh", "device.switch", height: 1, inactiveLabel: false, decoration: "flat") { - state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" - } - standardTile("softwhite", "device.softwhite", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offsoftwhite", label:"soft white", action:"softwhite", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onsoftwhite", label:"soft white", action:"softwhite", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFF1E0" - } - standardTile("daylight", "device.daylight", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offdaylight", label:"daylight", action:"daylight", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "ondaylight", label:"daylight", action:"daylight", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFB" - } - standardTile("warmwhite", "device.warmwhite", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offwarmwhite", label:"warm white", action:"warmwhite", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onwarmwhite", label:"warm white", action:"warmwhite", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFF4E5" - } - standardTile("red", "device.red", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offred", label:"red", action:"red", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onred", label:"red", action:"red", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FF0000" - } - standardTile("green", "device.green", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offgreen", label:"green", action:"green", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "ongreen", label:"green", action:"green", icon:"st.illuminance.illuminance.bright", backgroundColor:"#00FF00" - } - standardTile("blue", "device.blue", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offblue", label:"blue", action:"blue", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onblue", label:"blue", action:"blue", icon:"st.illuminance.illuminance.bright", backgroundColor:"#0000FF" - } - standardTile("cyan", "device.cyan", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offcyan", label:"cyan", action:"cyan", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "oncyan", label:"cyan", action:"cyan", icon:"st.illuminance.illuminance.bright", backgroundColor:"#00FFFF" - } - standardTile("magenta", "device.magenta", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offmagenta", label:"magenta", action:"magenta", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onmagenta", label:"magenta", action:"magenta", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FF00FF" - } - standardTile("orange", "device.orange", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offorange", label:"orange", action:"orange", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onorange", label:"orange", action:"orange", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FF6600" - } - standardTile("purple", "device.purple", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offpurple", label:"purple", action:"purple", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onpurple", label:"purple", action:"purple", icon:"st.illuminance.illuminance.bright", backgroundColor:"#BF00FF" - } - standardTile("yellow", "device.yellow", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offyellow", label:"yellow", action:"yellow", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onyellow", label:"yellow", action:"yellow", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFF00" - } - standardTile("white", "device.white", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offwhite", label:"White", action:"white", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onwhite", label:"White", action:"white", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" - } - standardTile("fireplace", "device.fireplace", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offfireplace", label:"Fire Place", action:"fireplace", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onfireplace", label:"Fire Place", action:"fireplace", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" - } - standardTile("storm", "device.storm", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offstorm", label:"storm", action:"storm", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onstorm", label:"storm", action:"storm", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" - } - standardTile("deepfade", "device.deepfade", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offdeepfade", label:"deep fade", action:"deepfade", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "ondeepfade", label:"deep fade", action:"deepfade", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" - } - standardTile("litefade", "device.litefade", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offlitefade", label:"lite fade", action:"litefade", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onlitefade", label:"lite fade", action:"litefade", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" - } - standardTile("police", "device.police", height: 1, inactiveLabel: false, canChangeIcon: false) { - state "offpolice", label:"police", action:"police", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" - state "onpolice", label:"police", action:"police", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" - } - controlTile("saturationSliderControl", "device.saturation", "slider", height: 1, width: 2, inactiveLabel: false) { + standardTile("refresh", "device.switch", height: 1, inactiveLabel: false, decoration: "flat") { + state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" + } + standardTile("softwhite", "device.softwhite", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offsoftwhite", label:"soft white", action:"softwhite", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onsoftwhite", label:"soft white", action:"softwhite", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFF1E0" + } + standardTile("daylight", "device.daylight", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offdaylight", label:"daylight", action:"daylight", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "ondaylight", label:"daylight", action:"daylight", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFB" + } + standardTile("warmwhite", "device.warmwhite", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offwarmwhite", label:"warm white", action:"warmwhite", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onwarmwhite", label:"warm white", action:"warmwhite", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFF4E5" + } + standardTile("red", "device.red", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offred", label:"red", action:"red", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onred", label:"red", action:"red", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FF0000" + } + standardTile("green", "device.green", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offgreen", label:"green", action:"green", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "ongreen", label:"green", action:"green", icon:"st.illuminance.illuminance.bright", backgroundColor:"#00FF00" + } + standardTile("blue", "device.blue", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offblue", label:"blue", action:"blue", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onblue", label:"blue", action:"blue", icon:"st.illuminance.illuminance.bright", backgroundColor:"#0000FF" + } + standardTile("cyan", "device.cyan", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offcyan", label:"cyan", action:"cyan", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "oncyan", label:"cyan", action:"cyan", icon:"st.illuminance.illuminance.bright", backgroundColor:"#00FFFF" + } + standardTile("magenta", "device.magenta", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offmagenta", label:"magenta", action:"magenta", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onmagenta", label:"magenta", action:"magenta", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FF00FF" + } + standardTile("orange", "device.orange", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offorange", label:"orange", action:"orange", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onorange", label:"orange", action:"orange", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FF6600" + } + standardTile("purple", "device.purple", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offpurple", label:"purple", action:"purple", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onpurple", label:"purple", action:"purple", icon:"st.illuminance.illuminance.bright", backgroundColor:"#BF00FF" + } + standardTile("yellow", "device.yellow", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offyellow", label:"yellow", action:"yellow", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onyellow", label:"yellow", action:"yellow", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFF00" + } + standardTile("white", "device.white", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offwhite", label:"White", action:"white", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onwhite", label:"White", action:"white", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" + } + standardTile("fireplace", "device.fireplace", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offfireplace", label:"Fire Place", action:"fireplace", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onfireplace", label:"Fire Place", action:"fireplace", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" + } + standardTile("storm", "device.storm", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offstorm", label:"storm", action:"storm", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onstorm", label:"storm", action:"storm", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" + } + standardTile("deepfade", "device.deepfade", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offdeepfade", label:"deep fade", action:"deepfade", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "ondeepfade", label:"deep fade", action:"deepfade", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" + } + standardTile("litefade", "device.litefade", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offlitefade", label:"lite fade", action:"litefade", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onlitefade", label:"lite fade", action:"litefade", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" + } + standardTile("police", "device.police", height: 1, inactiveLabel: false, canChangeIcon: false) { + state "offpolice", label:"police", action:"police", icon:"st.illuminance.illuminance.dark", backgroundColor:"#D8D8D8" + state "onpolice", label:"police", action:"police", icon:"st.illuminance.illuminance.bright", backgroundColor:"#FFFFFF" + } + controlTile("saturationSliderControl", "device.saturation", "slider", height: 1, width: 2, inactiveLabel: false) { state "saturation", action:"color control.setSaturation" } valueTile("saturation", "device.saturation", inactiveLabel: false, decoration: "flat") { - state "saturation", label: 'Sat ${currentValue} ' + state "saturation", label: 'Sat ${currentValue} ' } controlTile("hueSliderControl", "device.hue", "slider", height: 1, width: 2, inactiveLabel: false) { state "hue", action:"color control.setHue" } valueTile("hue", "device.hue", inactiveLabel: false, decoration: "flat") { - state "hue", label: 'Hue ${currentValue} ' + state "hue", label: 'Hue ${currentValue} ' } - main(["switch"]) - details(["switch", - "levelSliderControl", - "rgbSelector", - "whiteSliderControl", - /*"softwhite", - "daylight", - "warmwhite", - "red", - "green", - "blue", - "white", - "cyan", - "magenta", - "orange", - "purple", - "yellow", - "fireplace", - "storm", - "deepfade", - "litefade", - "police", - "power", - "configure",*/ - "refresh"]) + main(["switch"]) + details(["switch", + "levelSliderControl", + "rgbSelector", + "whiteSliderControl", + /*"softwhite", + "daylight", + "warmwhite", + "red", + "green", + "blue", + "white", + "cyan", + "magenta", + "orange", + "purple", + "yellow", + "fireplace", + "storm", + "deepfade", + "litefade", + "police", + "power", + "configure",*/ + "refresh"]) } } def setAdjustedColor(value) { log.debug "setAdjustedColor: ${value}" - toggleTiles("off") //turn off the hard color tiles + toggleTiles("off") //turn off the hard color tiles - def level = device.latestValue("level") - if(level == null) - level = 50 - log.debug "level is: ${level}" - value.level = level + def level = device.latestValue("level") + if(level == null) + level = 50 + log.debug "level is: ${level}" + value.level = level def c = hexToRgb(value.hex) value.rh = hex(c.r * (level/100)) value.gh = hex(c.g * (level/100)) value.bh = hex(c.b * (level/100)) - setColor(value) + setColor(value) } def setColor(value) { log.debug "setColor: ${value}" - log.debug "hue is: ${value.hue}" - log.debug "saturation is: ${value.saturation}" - - if (value.size() < 8) - toggleTiles("off") - - if (( value.size() == 2) && (value.hue != null) && (value.saturation != null)) { //assuming we're being called from outside of device (App) - def rgb = hslToRGB(value.hue, value.saturation, 0.5) - value.hex = rgbToHex(rgb) - value.rh = hex(rgb.r) - value.gh = hex(rgb.g) - value.bh = hex(rgb.b) - } - - if ((value.size() == 3) && (value.hue != null) && (value.saturation != null) && (value.level)) { //user passed in a level value too from outside (App) - def rgb = hslToRGB(value.hue, value.saturation, 0.5) - value.hex = rgbToHex(rgb) - value.rh = hex(rgb.r * value.level/100) - value.gh = hex(rgb.g * value.level/100) - value.bh = hex(rgb.b * value.level/100) - } - - if (( value.size() == 1) && (value.hex)) { //being called from outside of device (App) with only hex + log.debug "hue is: ${value.hue}" + log.debug "saturation is: ${value.saturation}" + + if (value.size() < 8) + toggleTiles("off") + + if (( value.size() == 2) && (value.hue != null) && (value.saturation != null)) { //assuming we're being called from outside of device (App) + def rgb = colorUtil.hslToRgb(value.hue / 100, value.saturation / 100, 0.5) + rgb = rgb.collect{Math.round(it) as int} + value.hex = colorUtil.rgbToHex(*rgb) + value.rh = hex(rgb[0]) + value.gh = hex(rgb[1]) + value.bh = hex(rgb[2]) + } + + if ((value.size() == 3) && (value.hue != null) && (value.saturation != null) && (value.level)) { //user passed in a level value too from outside (App) + def rgb = colorUtil.hslToRgb(value.hue / 100, value.saturation / 100, level.level / 100) + rgb = rgb.collect{Math.round(it) as int} + value.hex = colorUtil.rgbToHex(*rgb) + value.rh = hex(rgb[0]) + value.gh = hex(rgb[1]) + value.bh = hex(rgb[2]) + } + + if (( value.size() == 1) && (value.hex)) { //being called from outside of device (App) with only hex + def rgbInt = hexToRgb(value.hex) + value.rh = hex(rgbInt.r) + value.gh = hex(rgbInt.g) + value.bh = hex(rgbInt.b) + } + + if (( value.size() == 2) && (value.hex) && (value.level)) { //being called from outside of device (App) with only hex and level + def rgbInt = hexToRgb(value.hex) - value.rh = hex(rgbInt.r) - value.gh = hex(rgbInt.g) - value.bh = hex(rgbInt.b) - } - - if (( value.size() == 2) && (value.hex) && (value.level)) { //being called from outside of device (App) with only hex and level - - def rgbInt = hexToRgb(value.hex) - value.rh = hex(rgbInt.r * value.level/100) - value.gh = hex(rgbInt.g * value.level/100) - value.bh = hex(rgbInt.b * value.level/100) - } - - if (( value.size() == 1) && (value.colorName)) { //being called from outside of device (App) with only color name - def colorData = getColorData(value.colorName) - value.rh = colorData.rh - value.gh = colorData.gh - value.bh = colorData.bh - value.hex = "#${value.rh}${value.gh}${value.bh}" - } - - if (( value.size() == 2) && (value.colorName) && (value.level)) { //being called from outside of device (App) with only color name and level + value.rh = hex(rgbInt.r * value.level/100) + value.gh = hex(rgbInt.g * value.level/100) + value.bh = hex(rgbInt.b * value.level/100) + } + + if (( value.size() == 1) && (value.colorName)) { //being called from outside of device (App) with only color name def colorData = getColorData(value.colorName) - value.rh = hex(colorData.r * value.level/100) - value.gh = hex(colorData.g * value.level/100) - value.bh = hex(colorData.b * value.level/100) - value.hex = "#${hex(colorData.r)}${hex(colorData.g)}${hex(colorData.b)}" - } - - if (( value.size() == 3) && (value.red != null) && (value.green != null) && (value.blue != null)) { //being called from outside of device (App) with only color values (0-255) - value.rh = hex(value.red) - value.gh = hex(value.green) - value.bh = hex(value.blue) - value.hex = "#${value.rh}${value.gh}${value.bh}" - } - - if (( value.size() == 4) && (value.red != null) && (value.green != null) && (value.blue != null) && (value.level)) { //being called from outside of device (App) with only color values (0-255) and level - value.rh = hex(value.red * value.level/100) - value.gh = hex(value.green * value.level/100) - value.bh = hex(value.blue * value.level/100) - value.hex = "#${hex(value.red)}${hex(value.green)}${hex(value.blue)}" - } - - if(value.hue) { - sendEvent(name: "hue", value: value.hue, displayed: false) - } - if(value.saturation) { - sendEvent(name: "saturation", value: value.saturation, displayed: false) - } - if(value.hex?.trim()) { - sendEvent(name: "color", value: value.hex, displayed: false) - } - if (value.level) { - sendEvent(name: "level", value: value.level) - } - if (value.switch?.trim()) { - sendEvent(name: "switch", value: value.switch) - } - - sendRGB(value.rh, value.gh, value.bh) + value.rh = colorData.rh + value.gh = colorData.gh + value.bh = colorData.bh + value.hex = "#${value.rh}${value.gh}${value.bh}" + } + + if (( value.size() == 2) && (value.colorName) && (value.level)) { //being called from outside of device (App) with only color name and level + def colorData = getColorData(value.colorName) + value.rh = hex(colorData.r * value.level/100) + value.gh = hex(colorData.g * value.level/100) + value.bh = hex(colorData.b * value.level/100) + value.hex = "#${hex(colorData.r)}${hex(colorData.g)}${hex(colorData.b)}" + } + + if (( value.size() == 3) && (value.red != null) && (value.green != null) && (value.blue != null)) { //being called from outside of device (App) with only color values (0-255) + value.rh = hex(value.red) + value.gh = hex(value.green) + value.bh = hex(value.blue) + value.hex = "#${value.rh}${value.gh}${value.bh}" + } + + if (( value.size() == 4) && (value.red != null) && (value.green != null) && (value.blue != null) && (value.level)) { //being called from outside of device (App) with only color values (0-255) and level + value.rh = hex(value.red * value.level/100) + value.gh = hex(value.green * value.level/100) + value.bh = hex(value.blue * value.level/100) + value.hex = "#${hex(value.red)}${hex(value.green)}${hex(value.blue)}" + } + + if(value.hue) { + sendEvent(name: "hue", value: value.hue, displayed: false) + } + if(value.saturation) { + sendEvent(name: "saturation", value: value.saturation, displayed: false) + } + if(value.hex?.trim()) { + sendEvent(name: "color", value: value.hex, displayed: false) + } + if (value.level) { + sendEvent(name: "level", value: value.level) + } + if (value.switch?.trim()) { + sendEvent(name: "switch", value: value.switch) + } + + sendRGB(value.rh, value.gh, value.bh) } def setLevel(level, rate = null) { @@ -325,49 +327,49 @@ def setLevel(level, rate = null) { if (level == 0) { off() } else if (device.latestValue("switch") == "off") { on() } - def colorHex = device.latestValue("color") - if (colorHex == null) + def colorHex = device.latestValue("color") + if (colorHex == null) colorHex = "#FFFFFF" - def c = hexToRgb(colorHex) + def c = hexToRgb(colorHex) - def r = hex(c.r * (level/100)) - def g = hex(c.g * (level/100)) - def b = hex(c.b * (level/100)) + def r = hex(c.r * (level/100)) + def g = hex(c.g * (level/100)) + def b = hex(c.b * (level/100)) sendEvent(name: "level", value: level) - sendEvent(name: "setLevel", value: level, displayed: false) + sendEvent(name: "setLevel", value: level, displayed: false) sendRGB(r, g, b) } def setWhiteLevel(value) { log.debug "setWhiteLevel: ${value}" - def level = Math.min(value as Integer, 99) - level = 255 * level/99 as Integer - def channel = 0 + def level = Math.min(value as Integer, 99) + level = 255 * level/99 as Integer + def channel = 0 if (device.latestValue("switch") == "off") { on() } - sendEvent(name: "whiteLevel", value: value) - sendWhite(channel, value) + sendEvent(name: "whiteLevel", value: value) + sendWhite(channel, value) } def sendWhite(channel, value) { def whiteLevel = hex(value) - def cmd = [String.format("3305010${channel}${whiteLevel}%02X", 50)] - cmd + def cmd = [String.format("3305010${channel}${whiteLevel}%02X", 50)] + cmd } def sendRGB(redHex, greenHex, blueHex) { - def cmd = [String.format("33050302${redHex}03${greenHex}04${blueHex}%02X", 100),] - cmd + def cmd = [String.format("33050302${redHex}03${greenHex}04${blueHex}%02X", 100),] + cmd } def sendRGBW(redHex, greenHex, blueHex, whiteHex) { - def cmd = [String.format("33050400${whiteHex}02${redHex}03${greenHex}04${blueHex}%02X", 100),] - cmd + def cmd = [String.format("33050400${whiteHex}02${redHex}03${greenHex}04${blueHex}%02X", 100),] + cmd } @@ -376,16 +378,16 @@ def configure() { - def cmds = [] + def cmds = [] - // send associate to group 3 to get sensor data reported only to hub - cmds << zwave.associationV2.associationSet(groupingIdentifier:5, nodeId:[zwaveHubNodeId]).format() + // send associate to group 3 to get sensor data reported only to hub + cmds << zwave.associationV2.associationSet(groupingIdentifier:5, nodeId:[zwaveHubNodeId]).format() - //cmds << sendEvent(name: "level", value: 50) - //cmds << on() - //cmds << doColorButton("Green") - delayBetween(cmds, 500) + //cmds << sendEvent(name: "level", value: 50) + //cmds << on() + //cmds << doColorButton("Green") + delayBetween(cmds, 500) } @@ -397,15 +399,15 @@ def parse(String description) { isStateChange: false, displayed: false, descriptionText: description, - value: description + value: description ] def result def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 2, 0x72: 2, 0x60: 3, 0x33: 2, 0x32: 3, 0x31:2, 0x30: 2, 0x86: 1, 0x7A: 1]) - if (cmd) { - if ( cmd.CMD != "7006" ) { - result = createEvent(cmd, item1) - } + if (cmd) { + if ( cmd.CMD != "7006" ) { + result = createEvent(cmd, item1) + } } else { item1.displayed = displayed(description, item1.isStateChange) @@ -416,35 +418,35 @@ def parse(String description) { } def getDeviceData() { - def cmd = [] + def cmd = [] - cmd << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet()) - cmd << response(zwave.versionV1.versionGet()) + cmd << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet()) + cmd << response(zwave.versionV1.versionGet()) cmd << response(zwave.firmwareUpdateMdV1.firmwareMdGet()) - delayBetween(cmd, 500) + delayBetween(cmd, 500) } def createEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd, Map item1) { - log.debug "manufacturerName: ${cmd.manufacturerName}" - log.debug "manufacturerId: ${cmd.manufacturerId}" - log.debug "productId: ${cmd.productId}" - log.debug "productTypeId: ${cmd.productTypeId}" + log.debug "manufacturerName: ${cmd.manufacturerName}" + log.debug "manufacturerId: ${cmd.manufacturerId}" + log.debug "productId: ${cmd.productId}" + log.debug "productTypeId: ${cmd.productTypeId}" } def createEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd, Map item1) { - updateDataValue("applicationVersion", "${cmd.applicationVersion}") - log.debug "applicationVersion: ${cmd.applicationVersion}" - log.debug "applicationSubVersion: ${cmd.applicationSubVersion}" - log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}" - log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}" - log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}" + updateDataValue("applicationVersion", "${cmd.applicationVersion}") + log.debug "applicationVersion: ${cmd.applicationVersion}" + log.debug "applicationSubVersion: ${cmd.applicationSubVersion}" + log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}" + log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}" + log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}" } def createEvent(physicalgraph.zwave.commands.firmwareupdatemdv1.FirmwareMdReport cmd, Map item1) { - log.debug "checksum: ${cmd.checksum}" - log.debug "firmwareId: ${cmd.firmwareId}" - log.debug "manufacturerId: ${cmd.manufacturerId}" + log.debug "checksum: ${cmd.checksum}" + log.debug "firmwareId: ${cmd.firmwareId}" + log.debug "manufacturerId: ${cmd.manufacturerId}" } def zwaveEvent(physicalgraph.zwave.commands.colorcontrolv1.CapabilityReport cmd, Map item1) { @@ -453,94 +455,102 @@ def zwaveEvent(physicalgraph.zwave.commands.colorcontrolv1.CapabilityReport cmd, } def createEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, Map item1) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x26: 1, 0x30: 2, 0x32: 2, 0x33: 2]) // can specify command class versions here like in zwave.parse //log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}") if ((cmd.sourceEndPoint >= 1) && (cmd.sourceEndPoint <= 5)) { // we don't need color report - //don't do anything - } else { - if (encapsulatedCommand) { + //don't do anything + } else { + if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand) - } + } } } def createEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, Map item1) { - def result = doCreateEvent(cmd, item1) - for (int i = 0; i < result.size(); i++) { - result[i].type = "physical" - } - result + def result = doCreateEvent(cmd, item1) + for (int i = 0; i < result.size(); i++) { + result[i].type = "physical" + } + result } def createEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd, Map item1) { - def result = doCreateEvent(cmd, item1) - for (int i = 0; i < result.size(); i++) { - result[i].type = "physical" - } - result + def result = doCreateEvent(cmd, item1) + for (int i = 0; i < result.size(); i++) { + result[i].type = "physical" + } + result } def createEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd, Map item1) { - def result = [:] - if ( cmd.sensorType == 4 ) { //power level comming in - result.name = "power" - result.value = cmd.scaledSensorValue - result.descriptionText = "$device.displayName power usage is ${result.value} watt(s)" - result.isStateChange - sendEvent(name: result.name, value: result.value, displayed: false) - } - result + def result = [:] + if ( cmd.sensorType == 4 ) { //power level comming in + result.name = "power" + result.value = cmd.scaledSensorValue + result.descriptionText = "$device.displayName power usage is ${result.value} watt(s)" + result.isStateChange + sendEvent(name: result.name, value: result.value, displayed: false) + } + result } def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStartLevelChange cmd, Map item1) { - [] + [] } def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd, Map item1) { - [response(zwave.basicV1.basicGet())] + [response(zwave.basicV1.basicGet())] } def createEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelSet cmd, Map item1) { - def result = doCreateEvent(cmd, item1) - for (int i = 0; i < result.size(); i++) { - result[i].type = "physical" - } - result + def result = doCreateEvent(cmd, item1) + for (int i = 0; i < result.size(); i++) { + result[i].type = "physical" + } + result } def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd, Map item1) { - def result = doCreateEvent(cmd, item1) - result[0].descriptionText = "${item1.linkText} is ${item1.value}" - result[0].handlerName = cmd.value ? "statusOn" : "statusOff" - for (int i = 0; i < result.size(); i++) { - result[i].type = "digital" - } - result + def result = doCreateEvent(cmd, item1) + result[0].descriptionText = "${item1.linkText} is ${item1.value}" + result[0].handlerName = cmd.value ? "statusOn" : "statusOff" + for (int i = 0; i < result.size(); i++) { + result[i].type = "digital" + } + result } def doCreateEvent(physicalgraph.zwave.Command cmd, Map item1) { - def result = [item1] - - item1.name = "switch" - item1.value = cmd.value ? "on" : "off" - item1.handlerName = item1.value - item1.descriptionText = "${item1.linkText} was turned ${item1.value}" - item1.canBeCurrentState = true - item1.isStateChange = isStateChange(device, item1.name, item1.value) - item1.displayed = item1.isStateChange - - if (cmd.value >= 5) { - def item2 = new LinkedHashMap(item1) - item2.name = "level" - item2.value = (cmd.value == 99 ? 100 : cmd.value) as String - item2.unit = "%" - item2.descriptionText = "${item1.linkText} dimmed ${item2.value} %" - item2.canBeCurrentState = true - item2.isStateChange = isStateChange(device, item2.name, item2.value) - item2.displayed = false - result << item2 - } - result + def result = [item1] + + item1.name = "switch" + item1.value = cmd.value ? "on" : "off" + item1.handlerName = item1.value + item1.descriptionText = "${item1.linkText} was turned ${item1.value}" + item1.canBeCurrentState = true + item1.isStateChange = isStateChange(device, item1.name, item1.value) + item1.displayed = item1.isStateChange + + if (cmd.value >= 5) { + def item2 = new LinkedHashMap(item1) + item2.name = "level" + item2.value = (cmd.value == 99 ? 100 : cmd.value) as String + item2.unit = "%" + item2.descriptionText = "${item1.linkText} dimmed ${item2.value} %" + item2.canBeCurrentState = true + item2.isStateChange = isStateChange(device, item2.name, item2.value) + item2.displayed = false + result << item2 + } + result } def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd, item1) { @@ -548,23 +558,23 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport } /* def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { - log.debug "Report: $cmd" - def value = "when off" - if (cmd.configurationValue[0] == 1) {value = "when on"} - if (cmd.configurationValue[0] == 2) {value = "never"} - [name: "indicatorStatus", value: value, displayed: false] + log.debug "Report: $cmd" + def value = "when off" + if (cmd.configurationValue[0] == 1) {value = "when on"} + if (cmd.configurationValue[0] == 2) {value = "never"} + [name: "indicatorStatus", value: value, displayed: false] } */ -def createEvent(physicalgraph.zwave.Command cmd, Map map) { - // Handles any Z-Wave commands we aren't interested in - log.debug "UNHANDLED COMMAND $cmd" +def createEvent(physicalgraph.zwave.Command cmd, Map map) { + // Handles any Z-Wave commands we aren't interested in + log.debug "UNHANDLED COMMAND $cmd" } def on() { log.debug "on()" sendEvent(name: "switch", value: "on") delayBetween([zwave.basicV1.basicSet(value: 0xFF).format(), - zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000) + zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000) } def off() { @@ -575,13 +585,13 @@ def off() { def poll() { - zwave.switchMultilevelV1.switchMultilevelGet().format() + zwave.switchMultilevelV1.switchMultilevelGet().format() } def refresh() { def cmd = [] cmd << response(zwave.switchMultilevelV1.switchMultilevelGet().format()) - delayBetween(cmd, 500) + delayBetween(cmd, 500) } /** @@ -600,68 +610,68 @@ def refresh() { */ def updateZwaveParam(params) { if ( params ) { - def pNumber = params.paramNumber - def pSize = params.size - def pValue = [params.value] - log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'" + def pNumber = params.paramNumber + def pSize = params.size + def pValue = [params.value] + log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'" def cmds = [] - cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format() + cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format() - cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format() - delayBetween(cmds, 1500) - } + cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format() + delayBetween(cmds, 1500) + } } def test() { //def value = [:] - //value = [hue: 0, saturation: 100, level: 5] - //value = [red: 255, green: 0, blue: 255, level: 60] + //value = [hue: 0, saturation: 100, level: 5] + //value = [red: 255, green: 0, blue: 255, level: 60] //setColor(value) - def cmd = [] + def cmd = [] - if ( !state.cnt ) { - state.cnt = 6 - } else { - state.cnt = state.cnt + 1 - } + if ( !state.cnt ) { + state.cnt = 6 + } else { + state.cnt = state.cnt + 1 + } - if ( state.cnt > 10 ) - state.cnt = 6 + if ( state.cnt > 10 ) + state.cnt = 6 - // run programmed light show + // run programmed light show cmd << zwave.configurationV1.configurationSet(configurationValue: [state.cnt], parameterNumber: 72, size: 1).format() - cmd << zwave.configurationV1.configurationGet(parameterNumber: 72).format() + cmd << zwave.configurationV1.configurationGet(parameterNumber: 72).format() - delayBetween(cmd, 500) + delayBetween(cmd, 500) } def colorNameToRgb(color) { final colors = [ - [name:"Soft White", r: 255, g: 241, b: 224 ], - [name:"Daylight", r: 255, g: 255, b: 251 ], - [name:"Warm White", r: 255, g: 244, b: 229 ], + [name:"Soft White", r: 255, g: 241, b: 224 ], + [name:"Daylight", r: 255, g: 255, b: 251 ], + [name:"Warm White", r: 255, g: 244, b: 229 ], - [name:"Red", r: 255, g: 0, b: 0 ], - [name:"Green", r: 0, g: 255, b: 0 ], - [name:"Blue", r: 0, g: 0, b: 255 ], + [name:"Red", r: 255, g: 0, b: 0 ], + [name:"Green", r: 0, g: 255, b: 0 ], + [name:"Blue", r: 0, g: 0, b: 255 ], - [name:"Cyan", r: 0, g: 255, b: 255 ], - [name:"Magenta", r: 255, g: 0, b: 33 ], - [name:"Orange", r: 255, g: 102, b: 0 ], + [name:"Cyan", r: 0, g: 255, b: 255 ], + [name:"Magenta", r: 255, g: 0, b: 33 ], + [name:"Orange", r: 255, g: 102, b: 0 ], - [name:"Purple", r: 170, g: 0, b: 255 ], - [name:"Yellow", r: 255, g: 255, b: 0 ], - [name:"White", r: 255, g: 255, b: 255 ] + [name:"Purple", r: 170, g: 0, b: 255 ], + [name:"Yellow", r: 255, g: 255, b: 0 ], + [name:"White", r: 255, g: 255, b: 255 ] ] - def colorData = [:] - colorData = colors.find { it.name == color } + def colorData = [:] + colorData = colors.find { it.name == color } - colorData + colorData } private hex(value, width=2) { @@ -674,197 +684,163 @@ private hex(value, width=2) { def hexToRgb(colorHex) { def rrInt = Integer.parseInt(colorHex.substring(1,3),16) - def ggInt = Integer.parseInt(colorHex.substring(3,5),16) - def bbInt = Integer.parseInt(colorHex.substring(5,7),16) + def ggInt = Integer.parseInt(colorHex.substring(3,5),16) + def bbInt = Integer.parseInt(colorHex.substring(5,7),16) - def colorData = [:] - colorData = [r: rrInt, g: ggInt, b: bbInt] - colorData + def colorData = [:] + colorData = [r: rrInt, g: ggInt, b: bbInt] + colorData } def rgbToHex(rgb) { - def r = hex(rgb.r) - def g = hex(rgb.g) - def b = hex(rgb.b) - def hexColor = "#${r}${g}${b}" - - hexColor -} - -def hslToRGB(float var_h, float var_s, float var_l) { - float h = var_h / 100 - float s = var_s / 100 - float l = var_l - - def r = 0 - def g = 0 - def b = 0 - - if (s == 0) { - r = l * 255 - g = l * 255 - b = l * 255 - } else { - float var_2 = 0 - if (l < 0.5) { - var_2 = l * (1 + s) - } else { - var_2 = (l + s) - (s * l) - } + def r = hex(rgb.r) + def g = hex(rgb.g) + def b = hex(rgb.b) + def hexColor = "#${r}${g}${b}" - float var_1 = 2 * l - var_2 - - r = 255 * hueToRgb(var_1, var_2, h + (1 / 3)) - g = 255 * hueToRgb(var_1, var_2, h) - b = 255 * hueToRgb(var_1, var_2, h - (1 / 3)) - } - - def rgb = [:] - rgb = [r: r, g: g, b: b] - - rgb + hexColor } def hueToRgb(v1, v2, vh) { if (vh < 0) { vh += 1 } if (vh > 1) { vh -= 1 } if ((6 * vh) < 1) { return (v1 + (v2 - v1) * 6 * vh) } - if ((2 * vh) < 1) { return (v2) } - if ((3 * vh) < 2) { return (v1 + (v2 - v1) * ((2 / 3 - vh) * 6)) } - return (v1) + if ((2 * vh) < 1) { return (v2) } + if ((3 * vh) < 2) { return (v1 + (v2 - v1) * ((2 / 3 - vh) * 6)) } + return (v1) } def rgbToHSL(rgb) { def r = rgb.r / 255 - def g = rgb.g / 255 - def b = rgb.b / 255 - def h = 0 - def s = 0 - def l = 0 + def g = rgb.g / 255 + def b = rgb.b / 255 + def h = 0 + def s = 0 + def l = 0 - def var_min = [r,g,b].min() - def var_max = [r,g,b].max() - def del_max = var_max - var_min + def var_min = [r,g,b].min() + def var_max = [r,g,b].max() + def del_max = var_max - var_min - l = (var_max + var_min) / 2 + l = (var_max + var_min) / 2 - if (del_max == 0) { - h = 0 - s = 0 - } else { - if (l < 0.5) { s = del_max / (var_max + var_min) } - else { s = del_max / (2 - var_max - var_min) } + if (del_max == 0) { + h = 0 + s = 0 + } else { + if (l < 0.5) { s = del_max / (var_max + var_min) } + else { s = del_max / (2 - var_max - var_min) } - def del_r = (((var_max - r) / 6) + (del_max / 2)) / del_max - def del_g = (((var_max - g) / 6) + (del_max / 2)) / del_max - def del_b = (((var_max - b) / 6) + (del_max / 2)) / del_max + def del_r = (((var_max - r) / 6) + (del_max / 2)) / del_max + def del_g = (((var_max - g) / 6) + (del_max / 2)) / del_max + def del_b = (((var_max - b) / 6) + (del_max / 2)) / del_max - if (r == var_max) { h = del_b - del_g } - else if (g == var_max) { h = (1 / 3) + del_r - del_b } - else if (b == var_max) { h = (2 / 3) + del_g - del_r } + if (r == var_max) { h = del_b - del_g } + else if (g == var_max) { h = (1 / 3) + del_r - del_b } + else if (b == var_max) { h = (2 / 3) + del_g - del_r } if (h < 0) { h += 1 } - if (h > 1) { h -= 1 } + if (h > 1) { h -= 1 } } - def hsl = [:] - hsl = [h: h * 100, s: s * 100, l: l] + def hsl = [:] + hsl = [h: h * 100, s: s * 100, l: l] - hsl + hsl } def getColorData(colorName) { log.debug "getColorData: ${colorName}" - def colorRGB = colorNameToRgb(colorName) - def colorHex = rgbToHex(colorRGB) + def colorRGB = colorNameToRgb(colorName) + def colorHex = rgbToHex(colorRGB) def colorHSL = rgbToHSL(colorRGB) - def colorData = [:] - colorData = [h: colorHSL.h, - s: colorHSL.s, - l: device.latestValue("level"), - r: colorRGB.r, - g: colorRGB.g, - b: colorRGB.b, - rh: hex(colorRGB.r), - gh: hex(colorRGB.g), - bh: hex(colorRGB.b), - hex: colorHex, - alpha: 1] + def colorData = [:] + colorData = [h: colorHSL.h, + s: colorHSL.s, + l: device.latestValue("level"), + r: colorRGB.r, + g: colorRGB.g, + b: colorRGB.b, + rh: hex(colorRGB.r), + gh: hex(colorRGB.g), + bh: hex(colorRGB.b), + hex: colorHex, + alpha: 1] - colorData + colorData } def doColorButton(colorName) { - log.debug "doColorButton: '${colorName}()'" + log.debug "doColorButton: '${colorName}()'" - if (device.latestValue("switch") == "off") { on() } + if (device.latestValue("switch") == "off") { on() } - def level = device.latestValue("level") - def maxLevel = hex(99) + def level = device.latestValue("level") + def maxLevel = hex(99) - toggleTiles(colorName.toLowerCase().replaceAll("\\s","")) + toggleTiles(colorName.toLowerCase().replaceAll("\\s","")) - if ( colorName == "Fire Place" ) { updateZwaveParam([paramNumber:72, value:6, size:1]) } - else if ( colorName == "Storm" ) { updateZwaveParam([paramNumber:72, value:7, size:1]) } - else if ( colorName == "Deep Fade" ) { updateZwaveParam([paramNumber:72, value:8, size:1]) } - else if ( colorName == "Lite Fade" ) { updateZwaveParam([paramNumber:72, value:9, size:1]) } - else if ( colorName == "Police" ) { updateZwaveParam([paramNumber:72, value:10, size:1]) } - else if ( colorName == "White" ) { String.format("33050400${maxLevel}02${hex(0)}03${hex(0)}04${hex(0)}%02X", 100) } - else if ( colorName == "Daylight" ) { String.format("33050400${maxLevel}02${maxLevel}03${maxLevel}04${maxLevel}%02X", 100) } - else { + if ( colorName == "Fire Place" ) { updateZwaveParam([paramNumber:72, value:6, size:1]) } + else if ( colorName == "Storm" ) { updateZwaveParam([paramNumber:72, value:7, size:1]) } + else if ( colorName == "Deep Fade" ) { updateZwaveParam([paramNumber:72, value:8, size:1]) } + else if ( colorName == "Lite Fade" ) { updateZwaveParam([paramNumber:72, value:9, size:1]) } + else if ( colorName == "Police" ) { updateZwaveParam([paramNumber:72, value:10, size:1]) } + else if ( colorName == "White" ) { String.format("33050400${maxLevel}02${hex(0)}03${hex(0)}04${hex(0)}%02X", 100) } + else if ( colorName == "Daylight" ) { String.format("33050400${maxLevel}02${maxLevel}03${maxLevel}04${maxLevel}%02X", 100) } + else { def c = getColorData(colorName) def newValue = ["hue": c.h, "saturation": c.s, "level": level, "red": c.r, "green": c.g, "blue": c.b, "hex": c.hex, "alpha": c.alpha] - setColor(newValue) - def r = hex(c.r * (level/100)) - def g = hex(c.g * (level/100)) - def b = hex(c.b * (level/100)) - def w = hex(0) //to turn off white channel with toggling tiles + setColor(newValue) + def r = hex(c.r * (level/100)) + def g = hex(c.g * (level/100)) + def b = hex(c.b * (level/100)) + def w = hex(0) //to turn off white channel with toggling tiles sendRGBW(r, g, b, w) - } + } } def toggleTiles(color) { state.colorTiles = [] if ( !state.colorTiles ) { - state.colorTiles = ["softwhite","daylight","warmwhite","red","green","blue","cyan","magenta","orange","purple","yellow","white","fireplace","storm","deepfade","litefade","police"] - } + state.colorTiles = ["softwhite","daylight","warmwhite","red","green","blue","cyan","magenta","orange","purple","yellow","white","fireplace","storm","deepfade","litefade","police"] + } - def cmds = [] + def cmds = [] - state.colorTiles.each({ - if ( it == color ) { - log.debug "Turning ${it} on" - cmds << sendEvent(name: it, value: "on${it}", displayed: True, descriptionText: "${device.displayName} ${color} is 'ON'", isStateChange: true) - } else { - //log.debug "Turning ${it} off" - cmds << sendEvent(name: it, value: "off${it}", displayed: false) - } - }) + state.colorTiles.each({ + if ( it == color ) { + log.debug "Turning ${it} on" + cmds << sendEvent(name: it, value: "on${it}", displayed: True, descriptionText: "${device.displayName} ${color} is 'ON'", isStateChange: true) + } else { + //log.debug "Turning ${it} off" + cmds << sendEvent(name: it, value: "off${it}", displayed: false) + } + }) - delayBetween(cmds, 2500) + delayBetween(cmds, 2500) } // rows of buttons def softwhite() { doColorButton("Soft White") } -def daylight() { doColorButton("Daylight") } +def daylight() { doColorButton("Daylight") } def warmwhite() { doColorButton("Warm White") } -def red() { doColorButton("Red") } -def green() { doColorButton("Green") } -def blue() { doColorButton("Blue") } +def red() { doColorButton("Red") } +def green() { doColorButton("Green") } +def blue() { doColorButton("Blue") } -def cyan() { doColorButton("Cyan") } -def magenta() { doColorButton("Magenta") } -def orange() { doColorButton("Orange") } +def cyan() { doColorButton("Cyan") } +def magenta() { doColorButton("Magenta") } +def orange() { doColorButton("Orange") } def purple() { doColorButton("Purple") } -def yellow() { doColorButton("Yellow") } -def white() { doColorButton("White") } +def yellow() { doColorButton("Yellow") } +def white() { doColorButton("White") } def fireplace() { doColorButton("Fire Place") } -def storm() { doColorButton("Storm") } -def deepfade() { doColorButton("Deep Fade") } +def storm() { doColorButton("Storm") } +def deepfade() { doColorButton("Deep Fade") } -def litefade() { doColorButton("Lite Fade") } -def police() { doColorButton("Police") } +def litefade() { doColorButton("Lite Fade") } +def police() { doColorButton("Police") } diff --git a/devicetypes/smartthings/fibaro-smoke-sensor.src/fibaro-smoke-sensor.groovy b/devicetypes/smartthings/fibaro-smoke-sensor.src/fibaro-smoke-sensor.groovy index 7e02358dce8..d5c08dc86a7 100644 --- a/devicetypes/smartthings/fibaro-smoke-sensor.src/fibaro-smoke-sensor.groovy +++ b/devicetypes/smartthings/fibaro-smoke-sensor.src/fibaro-smoke-sensor.groovy @@ -22,11 +22,11 @@ metadata { capability "Tamper Alert" capability "Temperature Alarm" - fingerprint mfr:"010F", prod:"0C02", model:"1002" - fingerprint mfr:"010F", prod:"0C02", model:"4002" - fingerprint mfr:"010F", prod:"0C02", model:"1003" - fingerprint mfr:"010F", prod:"0C02" - fingerprint mfr:"010F", prod:"0C02", model:"3002" + fingerprint mfr:"010F", prod:"0C02", model:"1002", deviceJoinName: "Fibaro Smoke Detector" + fingerprint mfr:"010F", prod:"0C02", model:"4002", deviceJoinName: "Fibaro Smoke Detector" + fingerprint mfr:"010F", prod:"0C02", model:"1003", deviceJoinName: "Fibaro Smoke Detector" + fingerprint mfr:"010F", prod:"0C02", deviceJoinName: "Fibaro Smoke Detector" + fingerprint mfr:"010F", prod:"0C02", model:"3002", deviceJoinName: "Fibaro Smoke Detector" } simulator { //battery @@ -54,26 +54,26 @@ metadata { input description: "Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN", title: "To check smoke detection state", displayDuringSetup: true, type: "paragraph", element: "paragraph" input description: "Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings", - title: "Advanced Configuration", displayDuringSetup: true, type: "paragraph", element: "paragraph" - input "smokeSensorSensitivity", "enum", title: "Smoke Sensor Sensitivity", options: ["High","Medium","Low"], defaultValue: "${smokeSensorSensitivity}", displayDuringSetup: true - input "zwaveNotificationStatus", "enum", title: "Notifications Status", options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"], + title: "Advanced settings", displayDuringSetup: true, type: "paragraph", element: "paragraph" + input "smokeSensorSensitivity", "enum", title: "Smoke sensor sensitivity", options: ["High", "Medium", "Low"], defaultValue: "Medium", displayDuringSetup: true + input "zwaveNotificationStatus", "enum", title: "Notifications", options: ["None", "Casing opened", "Exceeding temperature threshold", "Lack of Z-Wave range", "All"], // defaultValue: "${zwaveNotificationStatus}", displayDuringSetup: true //Setting the default to casing opened so it can work in SmartThings mobile app. - defaultValue: "casing opened", displayDuringSetup: true - input "visualIndicatorNotificationStatus", "enum", title: "Visual Indicator Notifications Status", - options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"], - defaultValue: "${visualIndicatorNotificationStatus}", displayDuringSetup: true - input "soundNotificationStatus", "enum", title: "Sound Notifications Status", - options: ["disabled","casing opened","exceeding temperature threshold", "lack of Z-Wave range", "all notifications"], - defaultValue: "${soundNotificationStatus}", displayDuringSetup: true - input "temperatureReportInterval", "enum", title: "Temperature Report Interval", - options: ["reports inactive", "5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${temperatureReportInterval}", displayDuringSetup: true - input "temperatureReportHysteresis", "number", title: "Temperature Report Hysteresis", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true - input "temperatureThreshold", "number", title: "Overheat Temperature Threshold", description: "Available settings: 0 or 2-100 C", range: "0..100", displayDuringSetup: true - input "excessTemperatureSignalingInterval", "enum", title: "Excess Temperature Signaling Interval", - options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${excessTemperatureSignalingInterval}", displayDuringSetup: true - input "lackOfZwaveRangeIndicationInterval", "enum", title: "Lack of Z-Wave Range Indication Interval", - options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "${lackOfZwaveRangeIndicationInterval}", displayDuringSetup: true + defaultValue: "Casing opened", displayDuringSetup: true + input "visualIndicatorNotificationStatus", "enum", title: "Visual indicator notifications status", + options: ["None", "Casing opened", "Exceeding temperature threshold", "Lack of Z-Wave range", "All"], + defaultValue: "None", displayDuringSetup: true + input "soundNotificationStatus", "enum", title: "Sound notifications status", + options: ["None", "Casing opened", "Exceeding temperature threshold", "Lack of Z-Wave range", "All"], + defaultValue: "None", displayDuringSetup: true + input "temperatureReportInterval", "enum", title: "Temperature report interval", + options: ["Reports inactive", "5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "30 minutes", displayDuringSetup: true + input "temperatureReportHysteresis", "number", title: "Temperature report hysteresis", description: "Available settings: 1-100 C", range: "1..100", displayDuringSetup: true + input "temperatureThreshold", "number", title: "Overheat temperature threshold", description: "Available settings: 0 or 2-100 C", range: "0..100", displayDuringSetup: true + input "excessTemperatureSignalingInterval", "enum", title: "Excess temperature signaling interval", + options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "30 minutes", displayDuringSetup: true + input "lackOfZwaveRangeIndicationInterval", "enum", title: "Lack of Z-Wave range indication interval", + options: ["5 minutes", "15 minutes", "30 minutes", "1 hour", "6 hours", "12 hours", "18 hours", "24 hours"], defaultValue: "6 hours", displayDuringSetup: true } tiles (scale: 2){ multiAttributeTile(name:"smoke", type: "lighting", width: 6, height: 4){ @@ -119,9 +119,28 @@ metadata { def updated() { log.debug "Updated with settings: ${settings}" + if(!state.legacySettingsUpdated) updateLegacySettings() setConfigured("false") //wait until the next time device wakeup to send configure command } +def updateLegacySettings() { + + def legacyNotificationOptionMap = [ + "disabled" : "None", + "casing opened" : "Casing opened", + "exceeding temperature threshold" : "Exceeding temperature threshold", + "lack of Z-Wave range" : "Lack of Z-Wave range", + "all notifications" : "All" + ] + + device.updateSetting("temperatureReportInterval", temperatureReportInterval == "reports inactive" ?: "Reports inactive") + + device.updateSetting("zwaveNotificationStatus", legacyNotificationOptionMap[zwaveNotificationStatus] ?: zwaveNotificationStatus) + device.updateSetting("visualIndicatorNotificationStatus", legacyNotificationOptionMap[visualIndicatorNotificationStatus] ?: visualIndicatorNotificationStatus) + device.updateSetting("soundNotificationStatus", legacyNotificationOptionMap[soundNotificationStatus] ?: soundNotificationStatus) + + state.legacySettingsUpdated = true +} def parse(String description) { @@ -204,7 +223,7 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } def isFibaro() { - (zwaveInfo?.mfr == "010F" && zwaveInfo.prod == "0C02") + (zwaveInfo?.mfr?.equals("010F") && zwaveInfo?.prod?.equals("0C02")) } def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) { @@ -408,7 +427,7 @@ def configure() { ///3. Z-Wave notification status: 0-all disabled (default), 1-casing open enabled, 2-exceeding temp enable //if (state.initDefault) { // log.debug "Setting zwave notification default value to 1 "+zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: 1) - // request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: 1) + //request += zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: 1) // state.initDefault = false //} else if (zwaveNotificationStatus && zwaveNotificationStatus != "null"){ // log.debug "else zwave notification "+zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: notificationOptionValueMap[zwaveNotificationStatus] ?: 0) @@ -481,15 +500,15 @@ private def getTimeOptionValueMap() { [ "12 hours" : 4320, "18 hours" : 6480, "24 hours" : 8640, - "reports inactive" : 0, + "Reports inactive" : 0, ]} private def getNotificationOptionValueMap() { [ - "disabled" : 0, - "casing opened" : 1, - "exceeding temperature threshold" : 2, - "lack of Z-Wave range" : 4, - "all notifications" : 7, + "None" : 0, + "Casing opened" : 1, + "Exceeding temperature threshold" : 2, + "Lack of Z-Wave range" : 4, + "All" : 7, ]} private command(physicalgraph.zwave.Command cmd) { @@ -519,7 +538,7 @@ private setSecured() { private isSecured() { if (zwaveInfo && zwaveInfo.zw) { - return zwaveInfo.zw.endsWith("s") + return zwaveInfo.zw.contains("s") } else { return getDataValue("secured") == "true" } diff --git a/devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties b/devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties new file mode 100644 index 00000000000..f4577247cf5 --- /dev/null +++ b/devicetypes/smartthings/fibaro-smoke-sensor.src/i18n/messages.properties @@ -0,0 +1,1463 @@ +# Copyright 2020 SmartThings +# +# 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. + +# Device Preferences +'''Excess temperature signaling interval'''.en=Excess temperature signalling interval +'''Excess temperature signaling interval'''.en-gb=Excess temperature signalling interval +'''Excess temperature signaling interval'''.en-us=Excess temperature signaling interval +'''Excess temperature signaling interval'''.en-ca=Excess temperature signaling interval +'''Excess temperature signaling interval'''.sq=Intervali i sinjalizimit për tejkalim temperature +'''Excess temperature signaling interval'''.ar=الفاصل الزمني لإشارة تجاوز درجة الحرارة +'''Excess temperature signaling interval'''.be=Інтэрвал падачы сігналу аб празмернай тэмпературы +'''Excess temperature signaling interval'''.sr-ba=Interval signalizacije previsoke temperature +'''Excess temperature signaling interval'''.bg=Интервал на сигнализиране за превишена температура +'''Excess temperature signaling interval'''.ca=Interval de senyalització de temperatura excessiva +'''Excess temperature signaling interval'''.zh-cn=超过温度信号间隔 +'''Excess temperature signaling interval'''.zh-hk=超過溫度訊號時間間隔 +'''Excess temperature signaling interval'''.zh-tw=溫度超標訊號時間間隔 +'''Excess temperature signaling interval'''.hr=Interval signalizacije previsoke temperature +'''Excess temperature signaling interval'''.cs=Překročení intervalu signalizace teploty +'''Excess temperature signaling interval'''.da=Signalinterval ved for høj temperatur +'''Excess temperature signaling interval'''.nl=Signaalinterval hoge temperatuur +'''Excess temperature signaling interval'''.et=Liigsest temperatuurist märkuandmise välp +'''Excess temperature signaling interval'''.fi=Lämpötilan ylityksen ilmoitusaikaväli +'''Excess temperature signaling interval'''.fr=Intervalle de signalement du dépassement de température +'''Excess temperature signaling interval'''.fr-ca=Intervalle de signalement du dépassement de température +'''Excess temperature signaling interval'''.de=Übertemperatur-Signalintervall +'''Excess temperature signaling interval'''.el=Διάστημα σήμανσης υπερβολικής θερμοκρασίας +'''Excess temperature signaling interval'''.iw=מרווח איתות של טמפרטורה חריגה +'''Excess temperature signaling interval'''.hi-in=अत्यधिक तापमान संकेत अंतराल +'''Excess temperature signaling interval'''.hu=Pluszhőmérséklet jelzésének időköze +'''Excess temperature signaling interval'''.is=Tími milli tilkynninga um of háan hita +'''Excess temperature signaling interval'''.in=Interval sinyal suhu berlebih +'''Excess temperature signaling interval'''.it=Intervallo di segnalazione temperatura in eccesso +'''Excess temperature signaling interval'''.ja=温度超過を通知する間隔 +'''Excess temperature signaling interval'''.ko=과도한 온도 변화 알림 간격 +'''Excess temperature signaling interval'''.lv=Pārmērīgas temperatūras signalizācijas intervāls +'''Excess temperature signaling interval'''.lt=Viršytos temperatūros pranešimo intervalas +'''Excess temperature signaling interval'''.ms=Selang pengisyaratan suhu berlebihan +'''Excess temperature signaling interval'''.no=Intervall for signal om overskredet temperatur +'''Excess temperature signaling interval'''.pl=Interwał sygnalizowania zbyt wysokiej temperatury +'''Excess temperature signaling interval'''.pt=Intervalo de sinalização de temperatura excessiva +'''Excess temperature signaling interval'''.ro=Interval de semnalizare temperatură excesivă +'''Excess temperature signaling interval'''.ru=Интервал между сигналами о чрезмерном повышении температуры +'''Excess temperature signaling interval'''.sr=Interval signaliranja prekomerne temperature +'''Excess temperature signaling interval'''.sk=Interval signalizácie prekročenia teploty +'''Excess temperature signaling interval'''.sl=Interval signaliziranja prekomerne temperature +'''Excess temperature signaling interval'''.es=Intervalo de advertencia de exceso de temperatura +'''Excess temperature signaling interval'''.sv=Signalintervall för för hög temperatur +'''Excess temperature signaling interval'''.th=ช่วงเวลาการส่งสัญญาณอุณหภูมิส่วนเกิน +'''Excess temperature signaling interval'''.tr=Aşırı sıcaklık sinyali aralığı +'''Excess temperature signaling interval'''.uk=Інтервал сигналу про перевищення температури +'''Excess temperature signaling interval'''.vi=Chu kỳ báo hiệu nhiệt độ quá mức +'''Smoke sensor sensitivity'''.en=Smoke sensor sensitivity +'''Smoke sensor sensitivity'''.en-gb=Smoke sensor sensitivity +'''Smoke sensor sensitivity'''.en-us=Smoke sensor sensitivity +'''Smoke sensor sensitivity'''.en-ca=Smoke sensor sensitivity +'''Smoke sensor sensitivity'''.sq=Ndjeshmëria e sensorit të tymit +'''Smoke sensor sensitivity'''.ar=حساسية مستشعر الدخان +'''Smoke sensor sensitivity'''.be=Адчувальнасць датчыка дыму +'''Smoke sensor sensitivity'''.sr-ba=Osjetljivost senzora dima +'''Smoke sensor sensitivity'''.bg=Чувствителност на сензора за дим +'''Smoke sensor sensitivity'''.ca=Sensibilitat del sensor de fum +'''Smoke sensor sensitivity'''.zh-cn=烟雾传感器灵敏度 +'''Smoke sensor sensitivity'''.zh-hk=煙霧感應器靈敏度 +'''Smoke sensor sensitivity'''.zh-tw=煙霧偵測器靈敏度 +'''Smoke sensor sensitivity'''.hr=Osjetljivost senzora dima +'''Smoke sensor sensitivity'''.cs=Citlivost detektoru kouře +'''Smoke sensor sensitivity'''.da=Følsomhed af røgsensor +'''Smoke sensor sensitivity'''.nl=Gevoeligheid rooksensor +'''Smoke sensor sensitivity'''.et=Suitsuanduri tundlikkus +'''Smoke sensor sensitivity'''.fi=Savutunnistimen herkkyys +'''Smoke sensor sensitivity'''.fr=Sensibilité du détecteur de fumée +'''Smoke sensor sensitivity'''.fr-ca=Sensibilité du détecteur de fumée +'''Smoke sensor sensitivity'''.de=Rauchmelderempfindlichkeit +'''Smoke sensor sensitivity'''.el=Ευαισθησία αισθητήρα καπνού +'''Smoke sensor sensitivity'''.iw=רגישות חיישן העשן +'''Smoke sensor sensitivity'''.hi-in=स्मोक सेंसर की संवेदनशीलता +'''Smoke sensor sensitivity'''.hu=Füstérzékelő érzékenysége +'''Smoke sensor sensitivity'''.is=Næmi reykskynjara +'''Smoke sensor sensitivity'''.in=Sensitivitas sensor asap +'''Smoke sensor sensitivity'''.it=Sensibilità del rilevatore di fumo +'''Smoke sensor sensitivity'''.ja=煙センサーの感度 +'''Smoke sensor sensitivity'''.ko=연기 센서 민감도 +'''Smoke sensor sensitivity'''.lv=Dūmu sensora jutība +'''Smoke sensor sensitivity'''.lt=Dūmų jutiklio jautrumas +'''Smoke sensor sensitivity'''.ms=Kesensitifan penderia asap +'''Smoke sensor sensitivity'''.no=Røyksensorfølsomhet +'''Smoke sensor sensitivity'''.pl=Czułość czujnika dymu +'''Smoke sensor sensitivity'''.pt=Sensibilidade do sensor de fumo +'''Smoke sensor sensitivity'''.ro=Sensibilitate senzor de fum +'''Smoke sensor sensitivity'''.ru=Чувствительность датчика дыма +'''Smoke sensor sensitivity'''.sr=Osetljivost senzora dima +'''Smoke sensor sensitivity'''.sk=Citlivosť senzora dymu +'''Smoke sensor sensitivity'''.sl=Občutljivost senzorja dima +'''Smoke sensor sensitivity'''.es=Sensibilidad del sensor de humo +'''Smoke sensor sensitivity'''.sv=Brandvarnarens känslighet +'''Smoke sensor sensitivity'''.th=ความไวเซ็นเซอร์ควัน +'''Smoke sensor sensitivity'''.tr=Duman sensörü hassasiyeti +'''Smoke sensor sensitivity'''.uk=Чутливість датчика диму +'''Smoke sensor sensitivity'''.vi=Độ nhạy của cảm biến khói +'''Low'''.en=Low +'''Low'''.en-gb=Low +'''Low'''.en-us=Low +'''Low'''.en-ca=Low +'''Low'''.sq=E ulët +'''Low'''.ar=منخفضة +'''Low'''.be=Нізкая +'''Low'''.sr-ba=Nisko +'''Low'''.bg=Ниска +'''Low'''.ca=Baixa +'''Low'''.zh-cn=低 +'''Low'''.zh-hk=低 +'''Low'''.zh-tw=低 +'''Low'''.hr=Niska +'''Low'''.cs=Nízká +'''Low'''.da=Lav +'''Low'''.nl=Laag +'''Low'''.et=Madal +'''Low'''.fi=Pieni +'''Low'''.fr=Faible +'''Low'''.fr-ca=Faible +'''Low'''.de=Niedrig +'''Low'''.el=Χαμηλή +'''Low'''.iw=נמוכה +'''Low'''.hi-in=कम +'''Low'''.hu=Alacsony +'''Low'''.is=Lítið +'''Low'''.in=Rendah +'''Low'''.it=Bassa +'''Low'''.ja=低 +'''Low'''.ko=낮음 +'''Low'''.lv=Zems +'''Low'''.lt=Mažas +'''Low'''.ms=Rendah +'''Low'''.no=Lav +'''Low'''.pl=Niska +'''Low'''.pt=Baixa +'''Low'''.ro=Redusă +'''Low'''.ru=Низкая +'''Low'''.sr=Niska +'''Low'''.sk=Nízka +'''Low'''.sl=Nizko +'''Low'''.es=Baja +'''Low'''.sv=Lågt +'''Low'''.th=ต่ำ +'''Low'''.tr=Düşük +'''Low'''.uk=Низький +'''Low'''.vi=Thấp +'''Lack of Z-Wave range'''.en=Lack of Z-Wave range +'''Lack of Z-Wave range'''.en-gb=Lack of Z-Wave range +'''Lack of Z-Wave range'''.en-us=Lack of Z-Wave range +'''Lack of Z-Wave range'''.en-ca=Lack of Z-Wave range +'''Lack of Z-Wave range'''.sq=Mungon intervali Z-Wave +'''Lack of Z-Wave range'''.ar=غياب نطاق Z-Wave +'''Lack of Z-Wave range'''.be=Адсутнічае дыяпазон Z-Wave +'''Lack of Z-Wave range'''.sr-ba=Nedostatak opsega uređaja Z-Wave +'''Lack of Z-Wave range'''.bg=Липса на обхват на Z-Wave +'''Lack of Z-Wave range'''.ca=Interval de manca de senyal de Z-Wave +'''Lack of Z-Wave range'''.zh-cn=缺少 Z 波范围 +'''Lack of Z-Wave range'''.zh-hk=Z-Wave 範圍不足 +'''Lack of Z-Wave range'''.zh-tw=缺少 Z-Wave 覆蓋範圍 +'''Lack of Z-Wave range'''.hr=Nedostatak dometa uređaja Z-Wave +'''Lack of Z-Wave range'''.cs=Nedostatečný rozsah Z-Wave +'''Lack of Z-Wave range'''.da=Manglende Z-Wave-rækkevidde +'''Lack of Z-Wave range'''.nl=Slecht Z-Wave-bereik +'''Lack of Z-Wave range'''.et=Puudub Z-Wave’i vahemik +'''Lack of Z-Wave range'''.fi=Z-Wave-alueen puute +'''Lack of Z-Wave range'''.fr=Absence de réseau Z-Wave +'''Lack of Z-Wave range'''.fr-ca=Absence de réseau Z-Wave +'''Lack of Z-Wave range'''.de=Mangelnde Z-Wave-Reichweite +'''Lack of Z-Wave range'''.el=Έλλειψη εύρους Z-Wave +'''Lack of Z-Wave range'''.iw=Z-Wave מחוץ לטווח +'''Lack of Z-Wave range'''.hi-in=Z-Wave रेंज में कमी +'''Lack of Z-Wave range'''.hu=Hiányzó Z-Wave-hatótáv +'''Lack of Z-Wave range'''.is=Z-Wave-svæði vantar +'''Lack of Z-Wave range'''.in=Rentang kekurangan Gelombang-Z +'''Lack of Z-Wave range'''.it=Assenza di gamma Z-Wave +'''Lack of Z-Wave range'''.ja=Z-Waveレンジの不足 +'''Lack of Z-Wave range'''.ko=Z-Wave 네트워크 커뮤니케이션 부족 +'''Lack of Z-Wave range'''.lv=Nav Z-Wave diapazona +'''Lack of Z-Wave range'''.lt=Nėra „Z-Wave“ veikimo diapazono +'''Lack of Z-Wave range'''.ms=Kekurangan julat Z-Wave +'''Lack of Z-Wave range'''.no=Mangel på Z-Wave-område +'''Lack of Z-Wave range'''.pl=Brak zakresu Z-Wave +'''Lack of Z-Wave range'''.pt=Falta de alcance Z-Wave +'''Lack of Z-Wave range'''.ro=Z-Wave nu este în aria de acoperire +'''Lack of Z-Wave range'''.ru=Недостаточный диапазон Z-Wave +'''Lack of Z-Wave range'''.sr=Nedostatak Z-Wave opsega +'''Lack of Z-Wave range'''.sk=Nedostatočný rozsah Z-Wave +'''Lack of Z-Wave range'''.sl=Manjka doseg Z-Wave +'''Lack of Z-Wave range'''.es=Ausencia de alcance de Z-Wave +'''Lack of Z-Wave range'''.sv=Ett Z-Wave-intervall saknas +'''Lack of Z-Wave range'''.th=การขาดช่วง Z-Wave +'''Lack of Z-Wave range'''.tr=Z-Wave kapsamı yok +'''Lack of Z-Wave range'''.uk=Немає підключення до мережі Z-Wave +'''Lack of Z-Wave range'''.vi=Thiếu phạm vi Z-Wave +'''Lack of Z-Wave range indication interval'''.en=Lack of Z-Wave range indication interval +'''Lack of Z-Wave range indication interval'''.en-gb=Lack of Z-Wave range indication interval +'''Lack of Z-Wave range indication interval'''.en-us=Lack of Z-Wave range indication interval +'''Lack of Z-Wave range indication interval'''.en-ca=Lack of Z-Wave range indication interval +'''Lack of Z-Wave range indication interval'''.sq=Mungon intervali i treguesit për Z-Wave +'''Lack of Z-Wave range indication interval'''.ar=الفاصل الزمني لمؤشر غياب نطاق Z-Wave +'''Lack of Z-Wave range indication interval'''.be=Адсутнічае інтэрвал вызначэння дыяпазону Z-Wave +'''Lack of Z-Wave range indication interval'''.sr-ba=Nedostatak intervala indikacije opsega uređaja Z-Wave +'''Lack of Z-Wave range indication interval'''.bg=Липса на интервал за индикация на обхвата на Z-Wave +'''Lack of Z-Wave range indication interval'''.ca=Interval d'indicació de manca de senyal de Z-Wave +'''Lack of Z-Wave range indication interval'''.zh-cn=缺少 Z 波范围指示间隔 +'''Lack of Z-Wave range indication interval'''.zh-hk=Z-Wave 範圍指示時間間隔不足 +'''Lack of Z-Wave range indication interval'''.zh-tw=缺少 Z-Wave 覆蓋範圍指示時間間隔 +'''Lack of Z-Wave range indication interval'''.hr=Nedostatak intervala indikacije dometa uređaja Z-Wave +'''Lack of Z-Wave range indication interval'''.cs=Nedostatečný interval indikace rozsahu Z-Wave +'''Lack of Z-Wave range indication interval'''.da=Interval for indikation af manglende Z-Wave-rækkevidde +'''Lack of Z-Wave range indication interval'''.nl=Interval indicatie slecht Z-Wave-bereik +'''Lack of Z-Wave range indication interval'''.et=Puudub Z-Wave’i vahemiku näidustuse välp +'''Lack of Z-Wave range indication interval'''.fi=Z-Wave-alueen näyttöajan puute +'''Lack of Z-Wave range indication interval'''.fr=Intervalle d'indication de l'absence de réseau Z-Wave +'''Lack of Z-Wave range indication interval'''.fr-ca=Intervalle d'indication de l'absence de réseau Z-Wave +'''Lack of Z-Wave range indication interval'''.de=Anzeigeintervall bei mangelnder Z-Wave-Reichweite +'''Lack of Z-Wave range indication interval'''.el=Διάστημα έλλειψης ένδειξης εύρους Z-Wave +'''Lack of Z-Wave range indication interval'''.iw=מרווח ציון Z-Wave מחוץ לטווח +'''Lack of Z-Wave range indication interval'''.hi-in=Z-Wave रेंज में कमी संकेत का अंतराल +'''Lack of Z-Wave range indication interval'''.hu=Hiányzó Z-Wave-hatótávjelzési időköz +'''Lack of Z-Wave range indication interval'''.is=Tími milli tilkynninga um að Z-Wave-svæði vanti +'''Lack of Z-Wave range indication interval'''.in=Interval indikasi rentang kekurangan Gelombang-Z +'''Lack of Z-Wave range indication interval'''.it=Assenza di intervallo di indicazione gamma Z-Wave +'''Lack of Z-Wave range indication interval'''.ja=Z-Waveレンジの不足を指摘する間隔 +'''Lack of Z-Wave range indication interval'''.ko=Z-Wave 네트워크 커뮤니케이션 부족 표시 간격 +'''Lack of Z-Wave range indication interval'''.lv=Nav Z-Wave diapazona indikācijas intervāla +'''Lack of Z-Wave range indication interval'''.lt=„Z-Wave“ veikimo diapazono nebuvimo nurodymo intervalas +'''Lack of Z-Wave range indication interval'''.ms=Kekurangan selang penunjuk julat Z-Wave +'''Lack of Z-Wave range indication interval'''.no=Intervall for mangel på Z-Wave-områdeindikasjon +'''Lack of Z-Wave range indication interval'''.pl=Brak interwału wskazywania zakresu Z-Wave +'''Lack of Z-Wave range indication interval'''.pt=Falta de intervalo de indicação de alcance Z-Wave +'''Lack of Z-Wave range indication interval'''.ro=Interval de timp pentru a semnaliza că Z-Wave nu este în raza de acoperire +'''Lack of Z-Wave range indication interval'''.ru=Интервал индикации о недостаточном диапазоне Z-Wave +'''Lack of Z-Wave range indication interval'''.sr=Nedostatak intervala indikacije Z-Wave opsega +'''Lack of Z-Wave range indication interval'''.sk=Interval indikácie nedostatočného rozsahu Z-Wave +'''Lack of Z-Wave range indication interval'''.sl=Manjka interval za prikazovanje dosega Z-Wave +'''Lack of Z-Wave range indication interval'''.es=Intervalo de indicación de ausencia de alcance de Z-Wave +'''Lack of Z-Wave range indication interval'''.sv=Ett indikeringsintervall för Z-Wave-intervallet saknas +'''Lack of Z-Wave range indication interval'''.th=ระยะเวลาการระบุการขาดช่วง Z-Wave +'''Lack of Z-Wave range indication interval'''.tr=Z-Wave kapsam belirtimi aralığı yok +'''Lack of Z-Wave range indication interval'''.uk=Немає інтервалу індикації про підключення до мережі Z-Wave +'''Lack of Z-Wave range indication interval'''.vi=Chu kỳ chỉ báo thiếu phạm vi Z-Wave +'''Available settings: 0 or 2-100 C'''.en=When it's hotter than the temperature you set, you'll get a notification. You can set 0°C or 2-100°C. +'''Available settings: 0 or 2-100 C'''.en-gb=When it's hotter than the temperature you set, you'll get a notification. You can set 0°C or 2-100°C. +'''Available settings: 0 or 2-100 C'''.en-us=When it's hotter than the temperature you set, you'll get a notification. You can set 0°C or 2-100°C. +'''Available settings: 0 or 2-100 C'''.en-ca=When it's hotter than the temperature you set, you'll get a notification. You can set 0°C or 2-100°C. +'''Available settings: 0 or 2-100 C'''.sq=Do të marrësh një njoftim kur të jetë më nxehtë se temperatura që cilëson ti. Mund të cilësosh 0°C ose 2-100°C. +'''Available settings: 0 or 2-100 C'''.ar=عندما تصبح درجة الحرارة أكثر ارتفاعاً من تلك التي قمت بضبطها، ستتلقى إشعاراً. ويمكنك ضبط ۰ درجة مئوية أو ۲ - ۱۰۰ درجة مئوية. +'''Available settings: 0 or 2-100 C'''.be=Калі тэмпература перавысіць зададзеную, вы атрымаеце апавяшчэнне. Вы можаце задаць 0 °C або 2-100 °C. +'''Available settings: 0 or 2-100 C'''.sr-ba=Kada je temperatura viša od postavljene, primit ćete obavještenje. Možete postaviti 0°C ili raspon između 2°C i 100°C. +'''Available settings: 0 or 2-100 C'''.bg=Когато е по-горещо от зададената температура, ще получите уведомление. Може да зададете 0°C или 2 – 100°C. +'''Available settings: 0 or 2-100 C'''.ca=Quan la temperatura sigui superior a l'establerta, rebràs una notificació. Pots establir 0 °C o 2-100 °C. +'''Available settings: 0 or 2-100 C'''.zh-cn=当温度超过设置的温度时,您将收到通知。您可以设置 0°C 或 2-100°C。 +'''Available settings: 0 or 2-100 C'''.zh-hk=當溫度超過您設定的溫度時,您會收到通知。您可設定 0°C 或 2-100°C。 +'''Available settings: 0 or 2-100 C'''.zh-tw=溫度超過設定的熱度時,將傳送通知給您。您可設定 0°C 或 2 至 100°C 間的數值。 +'''Available settings: 0 or 2-100 C'''.hr=Kada je temperatura viša od postavljene, primit ćete obavijest. Možete postaviti 0 °C ili raspon između 2 °C i 100 °C. +'''Available settings: 0 or 2-100 C'''.cs=Když bude teplota vyšší než nastavená, budete upozorněni. Můžete nastavit teplotu 0 °C nebo 2-100 °C. +'''Available settings: 0 or 2-100 C'''.da=Du får en meddelelse, når det er varmere end den temperatur, du har angivet. Du kan angive 0 °C eller 2-100 °C. +'''Available settings: 0 or 2-100 C'''.nl=Als het warmer is dan de temperatuur die u hebt ingesteld, krijgt u een melding. U kunt 0°C of 2-100°C instellen. +'''Available settings: 0 or 2-100 C'''.et=Kui on kuumem, kui teie määratud tempreatuur, saate teavituse. Saate määrata 0 °C või 2 kuni 100 °C. +'''Available settings: 0 or 2-100 C'''.fi=Kun lämpötila ylittää asettamasi arvon, saat ilmoituksen. Voit asettaa arvoksi 0 °C tai 2–100 °C. +'''Available settings: 0 or 2-100 C'''.fr=Lorsqu'il fait plus chaud que la température que vous avez définie, vous recevez une notification. Vous pouvez régler la température sur 0 °C ou entre 2 et 100 °C. +'''Available settings: 0 or 2-100 C'''.fr-ca=Lorsqu'il fait plus chaud que la température que vous avez définie, vous recevez une notification. Vous pouvez régler la température sur 0 °C ou entre 2 et 100 °C. +'''Available settings: 0 or 2-100 C'''.de=Wenn die von Ihnen festgelegte Temperatur überschritten wird, erhalten Sie ein Benachrichtigung. Sie können 0°C oder einen Wert zwischen 2 und 100°C festlegen. +'''Available settings: 0 or 2-100 C'''.el=Όταν κάνει περισσότερη ζεστή από τη θερμοκρασία που έχετε ορίσει, θα λάβετε μια ειδοποίηση. Μπορείτε να ρυθμίσετε 0°C ή 2-100°C. +'''Available settings: 0 or 2-100 C'''.iw=כאשר הטמפרטורה גבוהה מזו שציינת, תקבל התראה. באפשרותך להגדיר 0°C או 2-100°C. +'''Available settings: 0 or 2-100 C'''.hi-in=जब यह आपके द्वारा सेट किए गए तापमान से अधिक गर्म होता है, तो आपको एक सूचना प्राप्त होगी। आप 0°C या 2-100°C सेट कर सकते हैं। +'''Available settings: 0 or 2-100 C'''.hu=Amikor melegebb van a beállított hőmérsékletnél, jelentést kap. 0 °C-ot vagy 2 és 100 °C közötti értéket adhat meg. +'''Available settings: 0 or 2-100 C'''.is=Þegar það er heitara en hitastigið sem þú stillir færðu tilkynningu. Hægt er að velja 0 °C eða 2–100 °C. +'''Available settings: 0 or 2-100 C'''.in=Saat suhu melebihi angka yang ditetapkan, Anda akan menerima notifikasi. Anda dapat menetapkan 0°C atau 2-100°C. +'''Available settings: 0 or 2-100 C'''.it=Quando la temperatura è superiore rispetto a quella impostata, si riceve una notifica. Potete impostare una temperatura di 0 o 2-100 °C. +'''Available settings: 0 or 2-100 C'''.ja=設定した温度より熱くなると、通知を受信します。0°Cまたは2~100°Cを設定できます。 +'''Available settings: 0 or 2-100 C'''.ko=설정한 온도보다 뜨거우면 알림을 받아요. 온도는 0°C 또는 2 - 100°C 사이로 설정할 수 있어요. +'''Available settings: 0 or 2-100 C'''.lv=Kad kļūs karstāks par jūsu iestatīto temperatūru, jūs saņemsit paziņojumu. Jūs varat iestatīt 0 °C vai 2-100 °C. +'''Available settings: 0 or 2-100 C'''.lt=Kai temperatūra bus aukštesnė nei nustatėte, gausite pranešimą. Galite nustatyti 0 °C arba 2–100 °C. +'''Available settings: 0 or 2-100 C'''.ms=Apabila suhu lebih panas daripada yang ditetapkan, anda akan menerima pemberitahuan. Anda boleh menetapkan 0°C atau 2-100°C. +'''Available settings: 0 or 2-100 C'''.no=Når det er varmere enn temperaturen du har angitt, får du et varsel. Du kan angi 0 °C eller 2–100 °C. +'''Available settings: 0 or 2-100 C'''.pl=Otrzymasz powiadomienie, gdy temperatura przekroczy ustawioną przez Ciebie wartość. Możesz ustawić 0°C lub 2–100°C. +'''Available settings: 0 or 2-100 C'''.pt=Quando estiver mais quente do que a temperatura que definir, receberá uma notificação. Pode definir 0 °C ou 2-100 °C. +'''Available settings: 0 or 2-100 C'''.ro=Atunci când temperatura o depășește pe cea setată, veți primi o notificare. Puteți seta 0 °C sau 2-100 °C. +'''Available settings: 0 or 2-100 C'''.ru=Если фактическая температура превысит заданную, вам поступит уведомление. Можно установить значение 0°C или 2–100°C. +'''Available settings: 0 or 2-100 C'''.sr=Kada je toplije od temperature koju ste podesili, dobićete obaveštenje. Možete da podesite 0°C ili 2–100°C. +'''Available settings: 0 or 2-100 C'''.sk=Keď prekročí nastavenú teplotu, dostanete oznámenie. Môžete nastaviť teplotu 0 °C alebo 2 až 100 °C. +'''Available settings: 0 or 2-100 C'''.sl=Ko je temperatura višja od nastavljene, boste prejeli obvestilo nastavite lahko 0 °C ali 2–100 °C. +'''Available settings: 0 or 2-100 C'''.es=Recibirás una notificación cuando la temperatura sea superior a la que establezcas. Puedes establecer 0 °C o 2-100 °C. +'''Available settings: 0 or 2-100 C'''.sv=När det är varmare än temperaturen som du anger får du en avisering. Du kan ange 0 °C eller 2–100 °C. +'''Available settings: 0 or 2-100 C'''.th=เมื่ออุณหภูมิร้อนขึ้นกว่าที่คุณตั้งค่าไว้ คุณจะได้รับการแจ้งเตือน คุณสามารถตั้งค่า 0°C หรือ 2-100°C ได้ +'''Available settings: 0 or 2-100 C'''.tr=Ortam, ayarladığınız değerden daha sıcak olduğunda bildirim alırsınız. 0 °C veya 2-100 °C arasında bir değeri ayarlayabilirsiniz. +'''Available settings: 0 or 2-100 C'''.uk=Якщо температура перевищить установлену, ви отримаєте сповіщення. Доступні значення: 0°C та 2–100°C. +'''Available settings: 0 or 2-100 C'''.vi=Khi nhiệt độ nóng hơn mức bạn đã đặt, bạn sẽ nhận được thông báo. Bạn có thể đặt 0°C hoặc 2-100°C. +'''Sound notifications status'''.en=Sound notifications +'''Sound notifications status'''.en-gb=Sound notifications +'''Sound notifications status'''.en-us=Sound notifications +'''Sound notifications status'''.en-ca=Sound notifications +'''Sound notifications status'''.sq=Njoftimet zanore +'''Sound notifications status'''.ar=إشعارات الصوت +'''Sound notifications status'''.be=Гукавыя апавяшчэнні +'''Sound notifications status'''.sr-ba=Zvučna obavještenja +'''Sound notifications status'''.bg=Звукови уведомления +'''Sound notifications status'''.ca=Notificacions de so +'''Sound notifications status'''.zh-cn=声音通知 +'''Sound notifications status'''.zh-hk=聲音通知 +'''Sound notifications status'''.zh-tw=音效通知 +'''Sound notifications status'''.hr=Zvučne obavijesti +'''Sound notifications status'''.cs=Zvuková oznámení +'''Sound notifications status'''.da=Lydmeddelelser +'''Sound notifications status'''.nl=Geluid meldingen +'''Sound notifications status'''.et=Heliteavitused +'''Sound notifications status'''.fi=Ääni-ilmoitukset +'''Sound notifications status'''.fr=Notifications sonores +'''Sound notifications status'''.fr-ca=Notifications sonores +'''Sound notifications status'''.de=Tonbenachrichtigungen +'''Sound notifications status'''.el=Ειδοποιήσεις ήχου +'''Sound notifications status'''.iw=התראות צליל +'''Sound notifications status'''.hi-in=ध्वनि सूचनाएँ +'''Sound notifications status'''.hu=Hangos értesítések +'''Sound notifications status'''.is=Hljóðviðvaranir +'''Sound notifications status'''.in=Notifikasi suara +'''Sound notifications status'''.it=Notifiche audio +'''Sound notifications status'''.ja=通知音 +'''Sound notifications status'''.ko=소리 알림 +'''Sound notifications status'''.lv=Skaņas paziņojumi +'''Sound notifications status'''.lt=Garso pranešimai +'''Sound notifications status'''.ms=Pemberitahuan bunyi +'''Sound notifications status'''.no=Lydvarsler +'''Sound notifications status'''.pl=Powiadomienia dźwiękowe +'''Sound notifications status'''.pt=Notificações de som +'''Sound notifications status'''.ro=Notificări sonore +'''Sound notifications status'''.ru=Звуковые уведомления +'''Sound notifications status'''.sr=Zvučna obaveštenja +'''Sound notifications status'''.sk=Zvukové oznámenia +'''Sound notifications status'''.sl=Zvočna obvestila +'''Sound notifications status'''.es=Notificaciones de sonido +'''Sound notifications status'''.sv=Ljudaviseringar +'''Sound notifications status'''.th=การแจ้งเตือนเสียง +'''Sound notifications status'''.tr=Sesli bildirimler +'''Sound notifications status'''.uk=Звукові сповіщення +'''Sound notifications status'''.vi=Thông báo âm thanh +'''24 hours'''.en=24 hours +'''24 hours'''.en-gb=24 hours +'''24 hours'''.en-us=24 hours +'''24 hours'''.en-ca=24 hours +'''24 hours'''.sq=24 orë +'''24 hours'''.ar=٢٤ ساعة +'''24 hours'''.be=24 гадзіны +'''24 hours'''.sr-ba=24 sata +'''24 hours'''.bg=24 часа +'''24 hours'''.ca=24 hores +'''24 hours'''.zh-cn=24 小时 +'''24 hours'''.zh-hk=24 小時 +'''24 hours'''.zh-tw=24 小時 +'''24 hours'''.hr=24 sata +'''24 hours'''.cs=24 hodin +'''24 hours'''.da=24 timer +'''24 hours'''.nl=24 uur +'''24 hours'''.et=24 tundi +'''24 hours'''.fi=24 tuntia +'''24 hours'''.fr=24 heures +'''24 hours'''.fr-ca=24 heures +'''24 hours'''.de=24 Stunden +'''24 hours'''.el=24 ώρες +'''24 hours'''.iw=24 שעות +'''24 hours'''.hi-in=24 घंटे +'''24 hours'''.hu=24 óra +'''24 hours'''.is=Sólarhringur +'''24 hours'''.in=24 jam +'''24 hours'''.it=24 ore +'''24 hours'''.ja=24時間 +'''24 hours'''.ko=24시간 +'''24 hours'''.lv=24 stundas +'''24 hours'''.lt=24 val. +'''24 hours'''.ms=24 jam +'''24 hours'''.no=24 timer +'''24 hours'''.pl=24 godziny +'''24 hours'''.pt=24 horas +'''24 hours'''.ro=24 de ore +'''24 hours'''.ru=24 часа +'''24 hours'''.sr=24 sata +'''24 hours'''.sk=24 hodín +'''24 hours'''.sl=24 ur +'''24 hours'''.es=24 horas +'''24 hours'''.sv=24 timmar +'''24 hours'''.th=24 ชั่วโมง +'''24 hours'''.tr=24 saat +'''24 hours'''.uk=24 години +'''24 hours'''.vi=24 giờ +'''Overheat temperature threshold'''.en=Overheat temperature threshold +'''Overheat temperature threshold'''.en-gb=Overheat temperature threshold +'''Overheat temperature threshold'''.en-us=Overheat temperature threshold +'''Overheat temperature threshold'''.en-ca=Overheat temperature threshold +'''Overheat temperature threshold'''.sq=Pragu i temp. për mbinxehje +'''Overheat temperature threshold'''.ar=حد درجة الحرارة المرتفعة +'''Overheat temperature threshold'''.be=Парог тэмпературы перагрэву +'''Overheat temperature threshold'''.sr-ba=Prag temperature pregrijavanja +'''Overheat temperature threshold'''.bg=Праг на температура на прегряване +'''Overheat temperature threshold'''.ca=Llindar de temperatura excessiva +'''Overheat temperature threshold'''.zh-cn=过热温度阈值 +'''Overheat temperature threshold'''.zh-hk=過熱溫度閾值 +'''Overheat temperature threshold'''.zh-tw=溫度過熱臨界值 +'''Overheat temperature threshold'''.hr=Prag temperature pregrijavanja +'''Overheat temperature threshold'''.cs=Prahová hodn. teploty přehřátí +'''Overheat temperature threshold'''.da=Tærskelværdi for overophedning +'''Overheat temperature threshold'''.nl=Grens temperatuur oververhitting +'''Overheat temperature threshold'''.et=Ülekuumenemise temperat. lävi +'''Overheat temperature threshold'''.fi=Ylikuumenemislämpötilan kynnysarvo +'''Overheat temperature threshold'''.fr=Seuil de surchauffe +'''Overheat temperature threshold'''.fr-ca=Seuil de surchauffe +'''Overheat temperature threshold'''.de=Überhitzungstemperatur-Grenzwert +'''Overheat temperature threshold'''.el=Όριο θερμοκρασίας υπερθέρμανσης +'''Overheat temperature threshold'''.iw=סף טמפרטורה של התחממות יתר +'''Overheat temperature threshold'''.hi-in=बहुत गर्म तापमान थ्रेसहोल्ड +'''Overheat temperature threshold'''.hu=Túlmelegedési küszöbhőmérséklet +'''Overheat temperature threshold'''.is=Viðmiðunmörk fyrir hitast. ofh. +'''Overheat temperature threshold'''.in=Ambang batas kelebihan suhu +'''Overheat temperature threshold'''.it=Soglia di surriscaldamento +'''Overheat temperature threshold'''.ja=高温閾値 +'''Overheat temperature threshold'''.ko=과열 온도 기준 +'''Overheat temperature threshold'''.lv=Pārkaršanas temp. slieksnis +'''Overheat temperature threshold'''.lt=Perkaitimo temperat. slenkstis +'''Overheat temperature threshold'''.ms=Ambang suhu terlampau panas +'''Overheat temperature threshold'''.no=Terskel for overtemperatur +'''Overheat temperature threshold'''.pl=Próg temperatury przegrzania +'''Overheat temperature threshold'''.pt=Limite de temp. sobreaquecimento +'''Overheat temperature threshold'''.ro=Prag temperatură supraîncălzire +'''Overheat temperature threshold'''.ru=Порог температуры перегрева +'''Overheat temperature threshold'''.sr=Granična vredn. temp. pregrevanja +'''Overheat temperature threshold'''.sk=Prah teploty prehriatia +'''Overheat temperature threshold'''.sl=Temperaturni prag pregrevanja +'''Overheat temperature threshold'''.es=Umbral de exceso de temperatura +'''Overheat temperature threshold'''.sv=Tröskel för överhettningstemp. +'''Overheat temperature threshold'''.th=ขอบเขตอุณหภูมิร้อนจัด +'''Overheat temperature threshold'''.tr=Aşırı ısınma sıcaklık eşiği +'''Overheat temperature threshold'''.uk=Поріг температури перегріву +'''Overheat temperature threshold'''.vi=Ngưỡng nhiệt độ quá nóng +'''Medium'''.en=Medium +'''Medium'''.en-gb=Medium +'''Medium'''.en-us=Medium +'''Medium'''.en-ca=Medium +'''Medium'''.sq=Mesatare +'''Medium'''.ar=متوسطة +'''Medium'''.be=Сярэдняя +'''Medium'''.sr-ba=Umjereno +'''Medium'''.bg=Средна +'''Medium'''.ca=Mitjana +'''Medium'''.zh-cn=中 +'''Medium'''.zh-hk=中 +'''Medium'''.zh-tw=中 +'''Medium'''.hr=Srednja +'''Medium'''.cs=Střední +'''Medium'''.da=Middel +'''Medium'''.nl=Gemiddeld +'''Medium'''.et=Keskmine +'''Medium'''.fi=Normaali +'''Medium'''.fr=Moyenne +'''Medium'''.fr-ca=Moyenne +'''Medium'''.de=Mittel +'''Medium'''.el=Μεσαία +'''Medium'''.iw=בינונית +'''Medium'''.hi-in=मध्‍यम +'''Medium'''.hu=Közepes +'''Medium'''.is=Miðlungs +'''Medium'''.in=Sedang +'''Medium'''.it=Media +'''Medium'''.ja=中 +'''Medium'''.ko=보통 +'''Medium'''.lv=Vidējs +'''Medium'''.lt=Vidutinis +'''Medium'''.ms=Sederhana +'''Medium'''.no=Middels +'''Medium'''.pl=Średnia +'''Medium'''.pt=Média +'''Medium'''.ro=Medie +'''Medium'''.ru=Средняя +'''Medium'''.sr=Srednja +'''Medium'''.sk=Stredná +'''Medium'''.sl=Srednje +'''Medium'''.es=Media +'''Medium'''.sv=Medel +'''Medium'''.th=ปานกลาง +'''Medium'''.tr=Orta +'''Medium'''.uk=Середній +'''Medium'''.vi=Trung bình +'''Advanced settings'''.en=Advanced settings +'''Advanced settings'''.en-gb=Advanced settings +'''Advanced settings'''.en-us=Advanced settings +'''Advanced settings'''.en-ca=Advanced settings +'''Advanced settings'''.en-ph=Advanced settings +'''Advanced settings'''.sq=Cilësime të avancuara +'''Advanced settings'''.ar=الضبط المتقدم +'''Advanced settings'''.be=Дадатковыя налады +'''Advanced settings'''.sr-ba=Napredne postavke +'''Advanced settings'''.bg=Разширени настройки +'''Advanced settings'''.ca=Ajustaments avançats +'''Advanced settings'''.zh-cn=高级设置 +'''Advanced settings'''.zh-hk=進階設定 +'''Advanced settings'''.zh-tw=進階設定 +'''Advanced settings'''.hr=Napredne postavke +'''Advanced settings'''.cs=Rozšířené nastavení +'''Advanced settings'''.da=Avancerede indstillinger +'''Advanced settings'''.nl=Geavanceerde instellingen +'''Advanced settings'''.et=Täpsemad seaded +'''Advanced settings'''.fi=Lisäasetukset +'''Advanced settings'''.fr=Paramètres avancés +'''Advanced settings'''.fr-ca=Paramètres avancés +'''Advanced settings'''.de=Erweiterte Einstellungen +'''Advanced settings'''.el=Σύνθετες ρυθμίσεις +'''Advanced settings'''.iw=הגדרות מתקדמות +'''Advanced settings'''.hi-in=उन्नत सेटिंग्स +'''Advanced settings'''.hu=Speciális beállítások +'''Advanced settings'''.is=Ítarlegar stillingar +'''Advanced settings'''.in=Pengaturan lanjutan +'''Advanced settings'''.it=Impostazioni avanzate +'''Advanced settings'''.ja=詳細設定 +'''Advanced settings'''.ko=고급 설정 +'''Advanced settings'''.lv=Papildu iestatījumi +'''Advanced settings'''.lt=Papildomi nustatymai +'''Advanced settings'''.ms=Aturan lanjutan +'''Advanced settings'''.no=Avanserte innstillinger +'''Advanced settings'''.pl=Ustawienia zaawansowane +'''Advanced settings'''.pt=Definições avançadas +'''Advanced settings'''.ro=Setări avansate +'''Advanced settings'''.ru=Дополнительные параметры +'''Advanced settings'''.sr=Napredna podešavanja +'''Advanced settings'''.sk=Rozšírené nastavenia +'''Advanced settings'''.sl=Napredne nastavitve +'''Advanced settings'''.es=Ajustes avanzados +'''Advanced settings'''.sv=Avancerade inställningar +'''Advanced settings'''.th=การตั้งค่าขั้นสูง +'''Advanced settings'''.tr=Gelişmiş ayarlar +'''Advanced settings'''.uk=Додаткові налаштування +'''Advanced settings'''.vi=Cài đặt nâng cao +'''Temperature report interval'''.en=Temperature report interval +'''Temperature report interval'''.en-gb=Temperature report interval +'''Temperature report interval'''.en-us=Temperature report interval +'''Temperature report interval'''.en-ca=Temperature report interval +'''Temperature report interval'''.sq=Intervali i raportit për temp. +'''Temperature report interval'''.ar=الفاصل الزمني لتقرير درجة الحرارة +'''Temperature report interval'''.be=Інтэрвал справаздач аб тэмпер +'''Temperature report interval'''.sr-ba=Interval izvješt. o temperaturi +'''Temperature report interval'''.bg=Интервал за отчитане на температ. +'''Temperature report interval'''.ca=Interval d'informe de temperatura +'''Temperature report interval'''.zh-cn=温度报告间隔 +'''Temperature report interval'''.zh-hk=溫度報告時間間隔 +'''Temperature report interval'''.zh-tw=溫度報告時間間隔 +'''Temperature report interval'''.hr=Interval izvješća o temperaturi +'''Temperature report interval'''.cs=Interval hlášení teploty +'''Temperature report interval'''.da=Interval for temperaturrapport +'''Temperature report interval'''.nl=Interval temperatuurrapport +'''Temperature report interval'''.et=Temperatuurist teavitamise välp +'''Temperature report interval'''.fi=Lämpötilaraportin aikaväli +'''Temperature report interval'''.fr=Intervalle rapport de température +'''Temperature report interval'''.fr-ca=Intervalle rapport de température +'''Temperature report interval'''.de=Temperaturberichtsintervall +'''Temperature report interval'''.el=Διάστημα αναφοράς θερμοκρασίας +'''Temperature report interval'''.iw=מרווח דוח טמפרטורה +'''Temperature report interval'''.hi-in=तापमान रिपोर्ट अंतराल +'''Temperature report interval'''.hu=Hőmérsékleti jelentési időköze +'''Temperature report interval'''.is=Tími á milli hitastigsskráninga +'''Temperature report interval'''.in=Interval laporan suhu +'''Temperature report interval'''.it=Intervallo report temperatura +'''Temperature report interval'''.ja=温度レポートの間隔 +'''Temperature report interval'''.ko=온도 알림 간격 +'''Temperature report interval'''.lv=Temperatūras ziņojuma intervāls +'''Temperature report interval'''.lt=Temperatūros praneš. intervalas +'''Temperature report interval'''.ms=Selang laporan suhu +'''Temperature report interval'''.no=Temperaturrapportintervall +'''Temperature report interval'''.pl=Interwał raportów o temperat. +'''Temperature report interval'''.pt=Intervalo do relatório temperatura +'''Temperature report interval'''.ro=Interval raportare temperatură +'''Temperature report interval'''.ru=Интервал отчета о температуре +'''Temperature report interval'''.sr=Interval izveštaja o temperaturi +'''Temperature report interval'''.sk=Interval hlásenia teploty +'''Temperature report interval'''.sl=Interval poročil o temperaturi +'''Temperature report interval'''.es=Intervalo de informe temperatura +'''Temperature report interval'''.sv=Intervall för temperaturrapport +'''Temperature report interval'''.th=ช่วงเวลารายงานอุณหภูมิ +'''Temperature report interval'''.tr=Sıcaklık raporlama aralığı +'''Temperature report interval'''.uk=Інтервал звіту про температуру +'''Temperature report interval'''.vi=Chu kỳ báo cáo nhiệt độ +'''Available settings: 1-100 C'''.en=Choose how much the temperature must differ from the previously reported temperature to send a new temperature report. You can enter a value from 1 to 100. The value you enter will be multiplied by 0.1. For example, if you enter 20, a report will be sent whenever the temperature changes by 2°C or more. +'''Available settings: 1-100 C'''.en-gb=Choose how much the temperature must differ from the previously reported temperature to send a new temperature report. You can enter a value from 1 to 100. The value you enter will be multiplied by 0.1. For example, if you enter 20, a report will be sent whenever the temperature changes by 2°C or more. +'''Available settings: 1-100 C'''.en-us=Choose how much the temperature must differ from the previously reported temperature to send a new temperature report. You can enter a value from 1 to 100. The value you enter will be multiplied by 0.1. For example, if you enter 20, a report will be sent whenever the temperature changes by 2°C or more. +'''Available settings: 1-100 C'''.en-ca=Choose how much the temperature must differ from the previously reported temperature to send a new temperature report. You can enter a value from 1 to 100. The value you enter will be multiplied by 0.1. For example, if you enter 20, a report will be sent whenever the temperature changes by 2°C or more. +'''Available settings: 1-100 C'''.sq=Zgjidh sa duhet të ndryshojë temperatura nga temperatura e raportuar më parë, që të dërgohet një raport i ri për temperaturën. Mund të futësh një vlerë nga 1 në 100. Vlera që fut do të shumëzohet me 0.1. Për shembull, në qoftë se fut 20, raporti do të dërgohet sa herë që temperatura ndryshon me 2°C ose më shumë. +'''Available settings: 1-100 C'''.ar=اختر القيمة التي يجب أن تختلف بها درجة الحرارة عن درجة الحرارة السابق الإبلاغ عنها لإرسال تقرير درجة الحرارة الجديد. ويمكنك إدخال قيمة من ۱ إلى ۱۰۰. وسيتم ضرب القيمة التي تقوم بإدخالها في ۰,۱. وعلى سبيل المثال، إذا قمت بإدخال ۲۰، سيتم إرسال تقرير عندما تتغير درجة الحرارة بـ ۲ درجة مئوية أو أكثر. +'''Available settings: 1-100 C'''.be=Выберыце, наколькі тэмпература павінна адрознівацца ад пазначанай у мінулай справаздачы для адпраўкі новай справаздачы. Вы можаце ўвесці значэнне ад 1 да 100. Уведзенае значэнне будзе памножана на 0,1. Напрыклад, калі ўвесці 20, справаздачы будуць адпраўляцца ў выпадку змянення тэмпературы на 2 °C або больш. +'''Available settings: 1-100 C'''.sr-ba=Izaberite koliko se temperatura mora razlikovati od prethodno prijavljene temperature u svrhu slanja novog izvještaja o temperaturi. Možete unijeti vrijednost od 1 do 100. Vrijednost koju unesete pomnožit će se s 0,1. Na primjer, ako unesete 20, izvještaj će se poslati kad god se temperatura promijeni za 2°C ili više. +'''Available settings: 1-100 C'''.bg=Изберете колко температурата трябва да се различава от отчетената по-рано температура, за да се изпрати нов отчет за температурата. Може да въведете стойност от 1 до 100. Стойността, която въведете, ще се умножи по 0,1. Например, ако въведете 20, всеки път ще се изпраща отчет, когато температурата се промени с 2°C или повече. +'''Available settings: 1-100 C'''.ca=Tria quant ha de diferir la temperatura respecte a la temperatura notificada anterior per enviar un nou informe de temperatura. Pots introduir un valor entre 1 i 100. El valor que introdueixis es multiplicarà per 0,1. Per exemple, si introdueixes 20, s'enviarà un informe quan la temperatura canviï 2 °C o més. +'''Available settings: 1-100 C'''.zh-cn=选择温度必须与以前报告的温度相差多少才能发送新的温度报告。您可以输入 1 到 100 之间的值。您输入的值将乘以 0.1。例如,如果输入 20,则每当温度变化超过 2°C 或更高时,就会发送报告。 +'''Available settings: 1-100 C'''.zh-hk=選擇當前溫度與之前報告的溫度必須相差多少才發送新的溫度報告。您可以輸入從 1 至 100 的值。您輸入的值將乘以 0.1。例如,若您輸入 20,則會在溫度變化 2°C 或以上時發送報告。 +'''Available settings: 1-100 C'''.zh-tw=請選擇目前溫度需與先前回報溫度有多大差異,才會傳送新的溫度報告。您可輸入 1 至 100 的數值。將以輸入的數值乘以 0.1 進行計算。舉例來說,如輸入 20,則只要溫差超過 2°C 以上,隨即自動傳送報告。 +'''Available settings: 1-100 C'''.hr=Odaberite koliko se temperatura mora razlikovati od prethodno prijavljene temperature u svrhu slanja novog izvješća o temperaturi. Možete unijeti vrijednost od 1 do 100. Vrijednost koju unesete pomnožit će se s 0,1. Na primjer, ako unesete 20, izvješće će se poslati kada se temperatura promijeni za 2 °C ili više. +'''Available settings: 1-100 C'''.cs=Zvolte, o kolik se musí teplota lišit od předchozí nahlášené teploty, aby byla zaslána nová zpráva o teplotě. Můžete zadat hodnotu od 1 do 100. Zadaná hodnota bude vynásobena koeficientem 0,1. Například když zadáte hodnotu 20, zpráva bude zaslána vždy, když se teplota změní o 2 °C nebo více. +'''Available settings: 1-100 C'''.da=Vælg, hvor meget temperaturen skal afvige fra den tidligere rapporterede temperatur, før der skal sendes en ny temperaturrapport. Du kan angive en værdi fra 1 til 100. Den værdi, du angiver, bliver ganget med 0,1. Så hvis du f.eks. angiver 20, så sendes der en rapport, når temperaturen varierer med 2 °C eller mere. +'''Available settings: 1-100 C'''.nl=Kies hoeveel de temperatuur moet verschillen van de eerder gerapporteerde temperatuur om een nieuw temperatuurrapport te sturen. U kunt een waarde tussen 1 en 100 invoeren. De waarde die u invoert, wordt vermenigvuldigd met 0,1. Als u bijvoorbeeld 20 invoert, wordt er een rapport verzonden wanneer de temperatuur 2°C of meer verschilt. +'''Available settings: 1-100 C'''.et=Valige, kui palju peab temperatuur erinema varasemalt teatatud temperatuurist, et saata uus temperatuuri aruanne. Saate sisestada väärtuse vahemikus 1 kuni 100. Sisestatud väärtus korrutatakse väärtusega 0,1. Näiteks, kui sisestate 20, saadetakse teade, kui temperatuur muutub 2 °C või rohkem. +'''Available settings: 1-100 C'''.fi=Valitse, kuinka paljon lämpötilan on poikettava viimeksi ilmoitetusta lämpötilasta, jotta lähetetään uusi lämpötilaraportti. Voit antaa arvoksi 1–100. Antamasi arvo kerrotaan 0,1:llä. Jos siis annat arvoksi esimerkiksi 20, raportti lähetetään, kun lämpötila muuttuu vähintään 2 °C. +'''Available settings: 1-100 C'''.fr=Déterminez de combien la température doit différer par rapport à la température signalée précédemment pour envoyer un rapport de nouvelle température. Vous pouvez entrer une valeur comprise entre 1 et 100. La valeur que vous entrez est multipliée par 0,1. Par exemple, si vous entrez 20, un rapport est envoyé lorsque la température varie d'au moins 2 °C. +'''Available settings: 1-100 C'''.fr-ca=Déterminez de combien la température doit différer par rapport à la température signalée précédemment pour envoyer un rapport de nouvelle température. Vous pouvez saisir une valeur comprise entre 1 et 100. La valeur que vous saisissez est multipliée par 0,1. Par exemple, si vous saisissez 20, un rapport est envoyé lorsque la température varie d'au moins 2 °C. +'''Available settings: 1-100 C'''.de=Wählen Sie aus, wie hoch der Unterschied zur zuvor gemeldeten Temperatur sein muss, damit ein neuer Temperaturbericht gesendet wird. Sie können einen Wert zwischen 1 und 100 eingeben. Der von Ihnen eingegebene Wert wird mit 0,1 multipliziert. Wenn Sie beispielsweise 20 eingeben, wird ein Bericht gesendet, wenn sich die Temperatur um mindestens 2°C ändert. +'''Available settings: 1-100 C'''.el=Επιλέξτε πόσο πρέπει να διαφέρει η θερμοκρασία από τη θερμοκρασία που αναφέρθηκε προηγουμένως για να στείλετε μια νέα αναφορά θερμοκρασίας. Μπορείτε να εισαγάγετε μια τιμή από 1 έως 100. Η τιμή που θα εισάγετε θα πολλαπλασιαστεί επί 0,1. Για παράδειγμα, εάν εισαγάγετε 20, μια αναφορά θα αποστέλλεται κάθε φορά που η θερμοκρασία αλλάζει κατά 2°C ή περισσότερο. +'''Available settings: 1-100 C'''.iw=בחר בכמה על הטמפרטורה לחרוג מהטמפרטורה שדווחה לאחרונה כדי שיישלח דוח טמפרטורה. ניתן להזין ערך בין 1 ל-100. הערך שתזין יוכפל פי 0.1. לדוגמה, אם תזין 20, יישלח דוח בכל פעם שהטמפרטורה משתנה ב-2°C או יותר. +'''Available settings: 1-100 C'''.hi-in=चुनें कि नई तापमान रिपोर्ट भेजने के लिए, तापमान पिछली बार रिपोर्ट किए तापमान से कितना भिन्न होना चाहिए। आप 1 से 100 तक का कोई मान प्रविष्ट कर सकते हैं। आपके द्वारा प्रविष्ट किए गए मान का 0.1 से गुणा किया जाएगा। जैसे कि, अगर आप 20 प्रविष्ट करते हैं, तो जब भी 2°C या उससे ज्यादा बदलता है, तब एक रिपोर्ट भेजी जाएगी। +'''Available settings: 1-100 C'''.hu=Válassza ki, hogy mennyivel kell eltérnie a hőmérsékletnek a korábban jelentettől ahhoz, hogy a rendszer új hőmérsékleti jelentést küldjön. 1 és 100 közötti értéket adhat meg. A megadott értéket a rendszer beszorozza 0,1-gyel. Ha például a 20 értéket adja meg, a hőmérséklet legalább 2 °C-os változásakor készül jelentés. +'''Available settings: 1-100 C'''.is=Veldu hversu mikil frávik mega vera í mælingum hitastigs miðað við fyrri skráningar á hitastigi til að ný hitastigsskýrsla verði send. Þú getur fært inn gildi frá 1 til 100. Gildið sem þú færir inn verður margfaldað með 0,1. Ef þú t.d. færir inn 20 verður send skýrsla í hvert sinn sem hitastigið breytist um 2 °C eða meira. +'''Available settings: 1-100 C'''.in=Pilih besar perbedaan suhu dari laporan suhu sebelumnya untuk mengirimkan laporan suhu yang baru. Anda dapat memasukkan angka dari 1 hingga 100. Angka yang dimasukkan akan dikalikan dengan 0,1. Contoh, jika Anda memasukkan angka 20, laporan akan dikirimkan setiap kali suhu berubah sebesar 2°C atau lebih. +'''Available settings: 1-100 C'''.it=Decidete di quanto deve differire la temperatura rispetto a quella segnalata in precedenza, per inviare un nuovo report sulla temperatura. Potete inserire un valore da 1 a 100, che verrà moltiplicato per 0,1. Se, per esempio, inserite 20, verrà inviato un report qualora la temperatura cambiasse di almeno 2 °C. +'''Available settings: 1-100 C'''.ja=前回のレポート時から温度が何度変化したら新しい温度レポートを送信するかを選択してください。1~100の値を入力できます。入力した値に0.1を掛けた値が求める温度になります。例えば、20と入力すると、温度が2°C以上変化したときにレポートが送信されます。 +'''Available settings: 1-100 C'''.ko=이전에 알린 온도보다 몇 도 높아졌을 때 알림을 받을지 선택해 주세요. 값은 1 - 100 사이로 입력할 수 있어요. 입력한 값에 0.1을 곱한 수만큼의 온도 변화에 따라 알림을 받아요. 예를 들어, 20을 입력했다면 온도가 2°C 이상 높아지면 알림을 받아요. +'''Available settings: 1-100 C'''.lv=Izvēlieties, cik lielai ir jābūt temperatūras atšķirībai no iepriekš uzrādītās temperatūras, lai jums tiktu nosūtīts jauns temperatūras ziņojums. Jūs varat ievadīt vērtību no 1 līdz 100. Ievadītā vērtība tiks reizināta ar 0,1. Piemēram, ja ievadīsit 20, ziņojums tiks nosūtīts ikreiz, kad temperatūra mainīsies par vismaz 2 °C. +'''Available settings: 1-100 C'''.lt=Pasirinkite, koks temperatūros skirtumas turi būti nuo anksčiau nurodytos temperatūros, kad būtų siunčiama nauja temperatūros ataskaita. Galite įvesti reikšmę nuo 1 iki 100. Jūsų įvesta reikšmė bus padauginta iš 0,1. Pavyzdžiui, jei įvesite 20, ataskaita bus siunčiama kaskart temperatūrai pasikeitus 2 °C ar daugiau. +'''Available settings: 1-100 C'''.ms=Pilih jumlah perbezaan suhu daripada laporan suhu sebelumnya untuk menghantar laporan suhu terbaru. Anda boleh masukkan nilai daripada 1 hingga 100. Nilai yang anda masukkan akan didarabkan dengan 0.1. Contohnya, jika anda memasukkan 20, laporan akan dihantar setiap kali suhu berubah sebanyak 2°C atau lebih. +'''Available settings: 1-100 C'''.no=Velg hvor mye temperaturen må avvike fra tidligere rapportert temperatur for å sende en ny temperaturrapport. Du kan angi en verdi fra 1 til 100. Verdien du angir, blir ganget med 0,1. Hvis du for eksempel angir 20, sendes en rapport når temperaturen endres med 2 °C eller mer. +'''Available settings: 1-100 C'''.pl=Wybierz, jak bardzo temperatura musi różnić się od poprzednio zarejestrowanej, aby wysłać nowy raport na temat temperatury. Możesz wprowadzić wartość od 1 do 100. Wprowadzona wartość zostanie pomnożona przez 0,1. Na przykład: jeśli wprowadzisz wartość 20, raport zostanie wysłany, gdy temperatura zmieni się o 2 stopnie lub więcej. +'''Available settings: 1-100 C'''.pt=Escolha a diferença de temperatura que tem de existir em relação à temperatura anteriormente reportada, para que seja enviado um novo relatório de temperatura. Pode introduzir um valor de 1 a 100. O valor introduzido será multiplicado por 0,1. Por exemplo, se introduzir 20, será enviado um relatório sempre que a temperatura se alterar em 2 °C ou mais. +'''Available settings: 1-100 C'''.ro=Alegeți cu cât trebuie să difere temperatura față de temperatura raportată anterior pentru a se trimite un nou raport de temperatură. Puteți introduce o valoare de la 1 la 100. Valoarea introdusă va fi înmulțită cu 0,1. De exemplu, dacă introduceți 20, va fi trimis un raport de fiecare dată când temperatura s-a modificat cu 2 °C sau mai mult. +'''Available settings: 1-100 C'''.ru=Укажите, при какой разнице между фактическим и ранее зарегистрированным значением температуры будет отправляться новый отчет о температуре. Можно ввести значение от 1 до 100. Указанное значение будет умножено на 0,1. Например, при вводе значения 20 отчет будет отправляться каждый раз, когда температура изменится на 2°C или более. +'''Available settings: 1-100 C'''.sr=Odaberite koliko temperatura mora da se razlikuje od prethodno prijavljene temperature da bi se poslala nova prijava temperature. Možete da unesete vrednost od 1 do 100. Vrednost koju unesete će biti pomnožena sa 0,1. Na primer, ako unesete 20, prijava će se poslati svaki put kada se temperatura promeni za 2°C ili više. +'''Available settings: 1-100 C'''.sk=Zvoľte, o koľko sa musí teplota líšiť od predchádzajúcej nahlásenej teploty, aby sa odoslala nová správa o teplote. Môžete zadať hodnotu od 1 do 100. Zadaná hodnota bude vynásobená koeficientom 0,1. Ak zadáte napríklad hodnotu 20, správa bude odoslaná vždy, keď sa teplota zmení o 2 °C alebo viac. +'''Available settings: 1-100 C'''.sl=Izberite, kolikšna mora biti temperaturna razlika glede na prejšnjo sporočeno temperaturo, da se bo poslalo novo poročilo o temperaturi. Vnesete lahko vrednost od 1 do 100. Vnesena vrednost bo pomnožena z 0,1. Če na primer vnesete 20, bo poročilo poslano, ko se temperatura spremeni za 2 °C ali več. +'''Available settings: 1-100 C'''.es=Elige qué diferencia de temperatura debe producirse con respecto a la temperatura comunicada anteriormente para enviar un nuevo informe de temperatura. Puedes introducir un valor de entre 1 y 100. El valor que introduzcas se multiplicará por 0,1. Por ejemplo, si introduces 20, se enviará un informe cuando la temperatura cambie en 2 °C o más. +'''Available settings: 1-100 C'''.sv=Välj hur mycket temperaturen måste skilja sig från den tidigare rapporterade temperaturen för att en ny temperaturrapport ska skickas. Du kan välja ett värde mellan 1 och 100. Värdet du anges multipliceras med 0,1. Om du t.ex. anger 20 skickas en rapport när temperaturen ändras med 2 °C eller mer. +'''Available settings: 1-100 C'''.th=เลือกว่าอุณหภูมิจะต้องแตกต่างจากอุณหภูมิที่รายงานก่อนหน้าเท่าใดจึงจะส่งรายงานอุณหภูมิใหม่ คุณสามารถใส่ค่าได้จาก 1 ถึง 100 ค่าที่คุณใส่จะถูกคูณด้วย 0.1 เช่น หากคุณใส่ 20 รายงานจะถูกส่งเมื่ออุณหภูมิเปลี่ยนไปอย่างน้อย 2°C +'''Available settings: 1-100 C'''.tr=Yeni bir sıcaklık raporu göndermek için önceden bildirilen sıcaklığa göre kaç derece farklılık olması gerektiğini seçin. 1-100 arasında bir değer girebilirsiniz. Girdiğiniz değer, 0,1 ile çarpılır. Örneğin, 20 değerini girerseniz sıcaklık 2 °C veya daha fazla değiştiğinde rapor gönderilir. +'''Available settings: 1-100 C'''.uk=Виберіть, наскільки температура має відрізнятися від раніше записаної для надсилання сповіщення про температуру. Можна ввести значення від 1 до 100, яке потім буде помножено на 0,1. Наприклад, якщо ввести 20, сповіщення надсилатиметься кожного разу, коли температура змінюватиметься на 2°C чи більше. +'''Available settings: 1-100 C'''.vi=Chọn mức nhiệt độ khác biệt với nhiệt độ đã báo cáo trước đó để gửi báo cáo nhiệt độ mới. Bạn có thể nhập một giá trị từ 1 đến 100. Giá trị bạn nhập sẽ được nhân với 0,1. Ví dụ, nếu bạn nhập 20, báo cáo sẽ được gửi mỗi khi nhiệt độ thay đổi từ 2°C trở lên. +'''To check smoke detection state'''.en=Checking the smoke detection state +'''To check smoke detection state'''.en-gb=Checking the smoke detection state +'''To check smoke detection state'''.en-us=Checking the smoke detection state +'''To check smoke detection state'''.en-ca=Checking the smoke detection state +'''To check smoke detection state'''.sq=Kontroll i statusit të pikasjes së tymit +'''To check smoke detection state'''.ar=التحقق من حالة اكتشاف الدخان +'''To check smoke detection state'''.be=Праверка стану выяўлення дыму +'''To check smoke detection state'''.sr-ba=Provjera stanja prepoznavanja dima +'''To check smoke detection state'''.bg=Проверка състоянието на откриване на дим +'''To check smoke detection state'''.ca=Comprovant l'estat de detecció de fums +'''To check smoke detection state'''.zh-cn=检查烟雾检测状态 +'''To check smoke detection state'''.zh-hk=檢查煙霧偵測器狀態 +'''To check smoke detection state'''.zh-tw=查看煙霧偵測狀態 +'''To check smoke detection state'''.hr=Provjera stanja prepoznavanja dima +'''To check smoke detection state'''.cs=Kontrola stavu detekce kouře +'''To check smoke detection state'''.da=Tjekker tilstand for registrering af røg +'''To check smoke detection state'''.nl=Status van de rookdetector controleren +'''To check smoke detection state'''.et=Suitsu tuvastamise oleku kontrollimine +'''To check smoke detection state'''.fi=Tarkistetaan savun tunnistuksen tilaa +'''To check smoke detection state'''.fr=Vérification état de détection de la fumée +'''To check smoke detection state'''.fr-ca=Vérification état de détection de la fumée +'''To check smoke detection state'''.de=Überprüfen des Raucherkennungsstatus +'''To check smoke detection state'''.el=Έλεγχος της κατάστασης ανίχνευσης καπνού +'''To check smoke detection state'''.iw=בודק את מצב זיהוי העשן +'''To check smoke detection state'''.hi-in=धुआँ पहचान की स्थिति जांचना +'''To check smoke detection state'''.hu=Füstérzékelés állapotának ellenőrzése +'''To check smoke detection state'''.is=Staða reykgreiningar athuguð +'''To check smoke detection state'''.in=Memeriksa status deteksi asap +'''To check smoke detection state'''.it=Verifica stato del rilevamento di fumo +'''To check smoke detection state'''.ja=煙の検出状況を確認 +'''To check smoke detection state'''.ko=연기 감지 상태 확인하기 +'''To check smoke detection state'''.lv=Dūmu noteikšanas stāvokļa pārbaude +'''To check smoke detection state'''.lt=Tikrinama dūmų detektoriaus būsena +'''To check smoke detection state'''.ms=Menyemak keadaan pengesanan asap +'''To check smoke detection state'''.no=Sjekker røykvarslerstatusen +'''To check smoke detection state'''.pl=Sprawdzanie stanu wykrywania dymu +'''To check smoke detection state'''.pt=Verificar o estado de detecção de fumo +'''To check smoke detection state'''.ro=Verificarea stării de detectare a fumului +'''To check smoke detection state'''.ru=Проверка сост. процесса обнаружения дыма +'''To check smoke detection state'''.sr=Proveravanje statusa detekcije dima +'''To check smoke detection state'''.sk=Kontrola stavu detekcie dymu +'''To check smoke detection state'''.sl=Preverjanje stanja zaznavanja dima +'''To check smoke detection state'''.es=Consultar estado de detección de humo +'''To check smoke detection state'''.sv=Kontrollerar brandvarnarens tillstånd +'''To check smoke detection state'''.th=การตรวจสอบสถานะการตรวจจับควัน +'''To check smoke detection state'''.tr=Duman algılama durumu kontrol ediliyor +'''To check smoke detection state'''.uk=Перевірка стану датчика диму +'''To check smoke detection state'''.vi=Kiểm tra trạng thái phát hiện khói +'''5 minutes'''.en=5 minutes +'''5 minutes'''.en-gb=5 minutes +'''5 minutes'''.en-us=5 minutes +'''5 minutes'''.en-ca=5 minutes +'''5 minutes'''.sq=5 minuta +'''5 minutes'''.ar=٥ دقائق +'''5 minutes'''.be=5 хвілін +'''5 minutes'''.sr-ba=5 minuta +'''5 minutes'''.bg=5 минути +'''5 minutes'''.ca=5 minuts +'''5 minutes'''.zh-cn=5 分钟 +'''5 minutes'''.zh-hk=5 分鐘 +'''5 minutes'''.zh-tw=5 分鐘 +'''5 minutes'''.hr=5 minuta +'''5 minutes'''.cs=5 minut +'''5 minutes'''.da=5 minutter +'''5 minutes'''.nl=5 minuten +'''5 minutes'''.et=5 minutit +'''5 minutes'''.fi=5 minuuttia +'''5 minutes'''.fr=5 minutes +'''5 minutes'''.fr-ca=5 minutes +'''5 minutes'''.de=5 Minuten +'''5 minutes'''.el=5 λεπτά +'''5 minutes'''.iw=5 דקות +'''5 minutes'''.hi-in=5 मिनट +'''5 minutes'''.hu=5 perc +'''5 minutes'''.is=5 mínútur +'''5 minutes'''.in=5 menit +'''5 minutes'''.it=5 minuti +'''5 minutes'''.ja=5分 +'''5 minutes'''.ko=5분 +'''5 minutes'''.lv=5 minūtes +'''5 minutes'''.lt=5 minutės +'''5 minutes'''.ms=5 minit +'''5 minutes'''.no=5 minutter +'''5 minutes'''.pl=5 minut +'''5 minutes'''.pt=5 minutos +'''5 minutes'''.ro=5 minute +'''5 minutes'''.ru=5 минут +'''5 minutes'''.sr=5 minuta +'''5 minutes'''.sk=5 minút +'''5 minutes'''.sl=5 minut +'''5 minutes'''.es=5 minutos +'''5 minutes'''.sv=5 minuter +'''5 minutes'''.th=5 นาที +'''5 minutes'''.tr=5 dakika +'''5 minutes'''.uk=5 хвилин +'''5 minutes'''.vi=5 phút +'''Exceeding temperature threshold'''.en=Temperature threshold exceeded +'''Exceeding temperature threshold'''.en-gb=Temperature threshold exceeded +'''Exceeding temperature threshold'''.en-us=Temperature threshold exceeded +'''Exceeding temperature threshold'''.en-ca=Temperature threshold exceeded +'''Exceeding temperature threshold'''.sq=U tejkalua caku i temperaturës +'''Exceeding temperature threshold'''.ar=تجاوز حد درجة الحرارة +'''Exceeding temperature threshold'''.be=Тэмпературны парог перавышаны +'''Exceeding temperature threshold'''.sr-ba=Prag temperature je prekoračen +'''Exceeding temperature threshold'''.bg=Температурният праг е надвишен +'''Exceeding temperature threshold'''.ca=S'ha excedit el llindar de temperatura +'''Exceeding temperature threshold'''.zh-cn=超过温度阈值 +'''Exceeding temperature threshold'''.zh-hk=超過溫度閾值 +'''Exceeding temperature threshold'''.zh-tw=超過溫度臨界值 +'''Exceeding temperature threshold'''.hr=Prag temperature premašen +'''Exceeding temperature threshold'''.cs=Prahová hodnota teploty překročena +'''Exceeding temperature threshold'''.da=Tærskelværdi for temp. overskredet +'''Exceeding temperature threshold'''.nl=Grens temperatuur overschreden +'''Exceeding temperature threshold'''.et=Temperatuuri lävi on ületatud +'''Exceeding temperature threshold'''.fi=Lämpötilan kynnysarvo ylitetty +'''Exceeding temperature threshold'''.fr=Seuil de température dépassé +'''Exceeding temperature threshold'''.fr-ca=Seuil de température dépassé +'''Exceeding temperature threshold'''.de=Temperaturgrenzwert überschritten +'''Exceeding temperature threshold'''.el=Υπέρβαση ορίου θερμοκρασίας +'''Exceeding temperature threshold'''.iw=סף הטמפרטורה נחצה +'''Exceeding temperature threshold'''.hi-in=तापमान थ्रेसहोल्ड बढ़ गया +'''Exceeding temperature threshold'''.hu=Küszöbhőmérséklet túllépve +'''Exceeding temperature threshold'''.is=Hitastig yfir viðmiðunarmörkum +'''Exceeding temperature threshold'''.in=Ambang batas suhu terlampaui +'''Exceeding temperature threshold'''.it=Soglia di surriscaldamento superata +'''Exceeding temperature threshold'''.ja=温度の閾値を超過 +'''Exceeding temperature threshold'''.ko=온도 기준 초과됨 +'''Exceeding temperature threshold'''.lv=Temperatūras slieksnis ir pārsniegts +'''Exceeding temperature threshold'''.lt=Viršytas temperatūros slenkstis +'''Exceeding temperature threshold'''.ms=Ambang suhu telah dilebihi +'''Exceeding temperature threshold'''.no=Temperaturterskel overskredet +'''Exceeding temperature threshold'''.pl=Przekroczono próg temperatury +'''Exceeding temperature threshold'''.pt=Limite de temperatura excedido +'''Exceeding temperature threshold'''.ro=Prag temperatură depășit +'''Exceeding temperature threshold'''.ru=Превышение температурного порога +'''Exceeding temperature threshold'''.sr=Granična vrednost temp. je premašena +'''Exceeding temperature threshold'''.sk=Prekročenie prahu teploty +'''Exceeding temperature threshold'''.sl=Temperaturni prag je prekoračen +'''Exceeding temperature threshold'''.es=Umbral de temperatura superado +'''Exceeding temperature threshold'''.sv=Temperaturtröskeln överskreds +'''Exceeding temperature threshold'''.th=เกินขอบเขตอุณหภูมิแล้ว +'''Exceeding temperature threshold'''.tr=Sıcaklık eşiği aşıldı +'''Exceeding temperature threshold'''.uk=Перевищено температурний поріг +'''Exceeding temperature threshold'''.vi=Đã vượt ngưỡng nhiệt độ +'''30 minutes'''.en=30 minutes +'''30 minutes'''.en-gb=30 minutes +'''30 minutes'''.en-us=30 minutes +'''30 minutes'''.en-ca=30 minutes +'''30 minutes'''.en-ph=30 minutes +'''30 minutes'''.sq=30 minuta +'''30 minutes'''.ar=٣٠ دقيقة +'''30 minutes'''.be=30 хвілін +'''30 minutes'''.sr-ba=30 minuta +'''30 minutes'''.bg=30 минути +'''30 minutes'''.ca=30 minuts +'''30 minutes'''.zh-cn=30 分钟 +'''30 minutes'''.zh-hk=30 分鐘 +'''30 minutes'''.zh-tw=30 分鐘 +'''30 minutes'''.hr=30 minuta +'''30 minutes'''.cs=30 minut +'''30 minutes'''.da=30 minutter +'''30 minutes'''.nl=30 minuten +'''30 minutes'''.et=30 minutit +'''30 minutes'''.fi=30 minuuttia +'''30 minutes'''.fr=30 minutes +'''30 minutes'''.fr-ca=30 minutes +'''30 minutes'''.de=30 Minuten +'''30 minutes'''.el=30 λεπτά +'''30 minutes'''.iw=30 דקות +'''30 minutes'''.hi-in=30 मिनट +'''30 minutes'''.hu=30 perc +'''30 minutes'''.is=30 mínútur +'''30 minutes'''.in=30 menit +'''30 minutes'''.it=30 minuti +'''30 minutes'''.ja=30分 +'''30 minutes'''.ko=30분 +'''30 minutes'''.lv=30 minūtes +'''30 minutes'''.lt=30 minučių +'''30 minutes'''.ms=30 minit +'''30 minutes'''.no=30 minutter +'''30 minutes'''.pl=30 minut +'''30 minutes'''.pt=30 minutos +'''30 minutes'''.ro=30 de minute +'''30 minutes'''.ru=30 минут +'''30 minutes'''.sr=30 minuta +'''30 minutes'''.sk=30 minút +'''30 minutes'''.sl=30 min +'''30 minutes'''.es=30 minutos +'''30 minutes'''.sv=30 minuter +'''30 minutes'''.th=30 นาที +'''30 minutes'''.tr=30 dakika +'''30 minutes'''.uk=30 хвилин +'''30 minutes'''.vi=30 phút +'''Instructions'''.en=Getting started +'''Instructions'''.en-gb=Getting started +'''Instructions'''.en-us=Getting started +'''Instructions'''.en-ca=Getting started +'''Instructions'''.en-ph=Getting started +'''Instructions'''.sq=Për të filluar +'''Instructions'''.ar=بدء الاستخدام +'''Instructions'''.be=Уводзіны +'''Instructions'''.sr-ba=Prvi koraci +'''Instructions'''.bg=Начално запознаване +'''Instructions'''.ca=Començar +'''Instructions'''.zh-cn=入门 +'''Instructions'''.zh-hk=快速入門 +'''Instructions'''.zh-tw=開始使用 +'''Instructions'''.hr=Početak rada +'''Instructions'''.cs=Začínáme +'''Instructions'''.da=Kom godt i gang +'''Instructions'''.nl=Aan de slag +'''Instructions'''.et=Alustamine +'''Instructions'''.fi=Käytön aloittaminen +'''Instructions'''.fr=Démarrer +'''Instructions'''.fr-ca=Démarrer +'''Instructions'''.de=Erste Schritte +'''Instructions'''.el=Έναρξη +'''Instructions'''.iw=תחילת העבודה +'''Instructions'''.hi-in=प्रारंभ करना +'''Instructions'''.hu=Első lépések +'''Instructions'''.is=Hafist handa +'''Instructions'''.in=Mulai +'''Instructions'''.it=Introduzione +'''Instructions'''.ja=はじめに +'''Instructions'''.ko=빅스비와 대화하기 +'''Instructions'''.lv=Darba sākšana +'''Instructions'''.lt=Darbo pradžia +'''Instructions'''.ms=Bermula +'''Instructions'''.no=Komme i gang +'''Instructions'''.pl=Pierwsze kroki +'''Instructions'''.pt=Introdução +'''Instructions'''.ro=Primii pași +'''Instructions'''.ru=Введение +'''Instructions'''.sr=Prvi koraci +'''Instructions'''.sk=Začíname +'''Instructions'''.sl=Vodnik za začetek +'''Instructions'''.es=Primeros pasos +'''Instructions'''.sv=Komma igång +'''Instructions'''.th=เริ่มต้น +'''Instructions'''.tr=Başlarken +'''Instructions'''.uk=Початок роботи +'''Instructions'''.vi=Bắt đầu sử dụng +'''High'''.en=High +'''High'''.en-gb=High +'''High'''.en-us=High +'''High'''.en-ca=High +'''High'''.sq=E lartë +'''High'''.ar=عالية +'''High'''.be=Высокая +'''High'''.sr-ba=Visoko +'''High'''.bg=Висока +'''High'''.ca=Alta +'''High'''.zh-cn=高 +'''High'''.zh-hk=高 +'''High'''.zh-tw=高 +'''High'''.hr=Visoka +'''High'''.cs=Vysoká +'''High'''.da=Høj +'''High'''.nl=Hoog +'''High'''.et=Kõrge +'''High'''.fi=Suuri +'''High'''.fr=Élevée +'''High'''.fr-ca=Élevée +'''High'''.de=Hoch +'''High'''.el=Υψηλή +'''High'''.iw=גבוהה +'''High'''.hi-in=उच्च +'''High'''.hu=Magas +'''High'''.is=Mikið +'''High'''.in=Tinggi +'''High'''.it=Alta +'''High'''.ja=高 +'''High'''.ko=높음 +'''High'''.lv=Augsts +'''High'''.lt=Didelis +'''High'''.ms=Tinggi +'''High'''.no=Høy +'''High'''.pl=Wysoka +'''High'''.pt=Alta +'''High'''.ro=Ridicată +'''High'''.ru=Высокая +'''High'''.sr=Visoka +'''High'''.sk=Vysoká +'''High'''.sl=Visoko +'''High'''.es=Alta +'''High'''.sv=Högt +'''High'''.th=สูง +'''High'''.tr=Yüksek +'''High'''.uk=Високий +'''High'''.vi=Cao +'''None'''.en=None +'''None'''.en-gb=None +'''None'''.en-us=None +'''None'''.en-ca=None +'''None'''.en-ph=None +'''None'''.sq=Asnjë +'''None'''.ar=بلا +'''None'''.be=Няма +'''None'''.sr-ba=Nema +'''None'''.bg=Няма +'''None'''.ca=Cap +'''None'''.zh-cn=无 +'''None'''.zh-hk=無 +'''None'''.zh-tw=無 +'''None'''.hr=Ništa +'''None'''.cs=Žádná +'''None'''.da=Ingen +'''None'''.nl=Geen +'''None'''.et=Puudub +'''None'''.fi=Ei mitään +'''None'''.fr=Aucune +'''None'''.fr-ca=Aucune +'''None'''.de=Keine +'''None'''.el=Κανένα +'''None'''.iw=ללא +'''None'''.hi-in=कुछ भी नहीं +'''None'''.hu=Egyik sem +'''None'''.is=Ekkert +'''None'''.in=Tidak ada +'''None'''.it=Nessuna +'''None'''.ja=なし +'''None'''.ko=설정 안 함 +'''None'''.lv=Nav +'''None'''.lt=Nėra +'''None'''.ms=Tiada +'''None'''.no=Ingen +'''None'''.pl=Brak +'''None'''.pt=Nenhum +'''None'''.ro=Niciuna +'''None'''.ru=Нет +'''None'''.sr=Ništa +'''None'''.sk=Žiadne +'''None'''.sl=Brez +'''None'''.es=Ninguno +'''None'''.sv=Inget +'''None'''.th=ไม่มี +'''None'''.tr=Hiçbiri +'''None'''.uk=Немає +'''None'''.vi=Không có +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.en=Check the manual that came with your Fibaro Smoke Sensor for information about advanced settings. If you don't make any changes below, the default settings will be used. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.en-gb=Check the manual that came with your Fibaro Smoke Sensor for information about advanced settings. If you don't make any changes below, the default settings will be used. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.en-us=Check the manual that came with your Fibaro Smoke Sensor for information about advanced settings. If you don't make any changes below, the default settings will be used. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.en-ca=Check the manual that came with your Fibaro Smoke Sensor for information about advanced settings. If you don't make any changes below, the default settings will be used. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.sq=Shiko në manualin që të erdhi me Sensorin e Tymit Fibaro për informacion rreth cilësimeve të avancuara. Në qoftë se nuk bën ndryshime më poshtë, do të përdoren cilësimet e parazgjedhura. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.ar=راجع الدليل المرفق مع مستشعر الدخان Fibaro الخاص بك للحصول على معلومات حول الضبط المتقدم. إذا لم تقم بإجراء أي من التغييرات التالية، فسيتم استخدام الضبط الافتراضي. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.be=Інфармацыю аб дадатковых наладах вы знойдзеце ў дапаможніку, які пастаўляўся з датчыкам дыму Fibaro. Калі вы не зменіце нічога ніжэй, будуць выкарыстоўвацца стандартныя налады. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.sr-ba=Provjerite uputstvo koji ste dobili zajedno sa senzorom dima kompanije Fibaro za informacije o naprednim postavkama. Ako ne izvršite promjene u nastavku, koristit će se zadane postavke. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.bg=Прегледайте ръководството, приложено към сензора за дим Fibaro, за информация относно разширените настройки. Ако не направите промени по-долу, ще бъдат използвани настройките по подразбиране. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.ca=Consulta el manual inclòs amb el sensor de fum Fibaro per obtenir informació sobre els ajustaments avançats. Si no fas canvis a continuació, s'utilitzaran els ajustaments predeterminats. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.zh-cn=有关高级设置的信息,请查看 Fibaro 烟雾传感器随附的手册。如果未在下面进行任何更改,将使用默认设置。 +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.zh-hk=查看 Fibaro 煙霧偵測器隨附的手冊,瞭解關於進階設定的資訊。若您沒有進行以下任何變更,將使用預設設定。 +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.zh-tw=請查看 Fibaro 煙霧偵測器隨附的使用說明書,瞭解進階設定相關資訊。如未於下方進行任何變更,則會使用預設設定。 +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.hr=Provjerite priručnik koji ste dobili uz senzor dima tvrtke Fibaro za informacije o naprednim postavkama. Ako ne izvršite promjene u nastavku, upotrebljavat će se zadane postavke. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.cs=Informace o pokročilém nastavení najdete v návodu k použití detektoru kouře Fibaro. Pokud neprovedete níže žádné změny, budou použita výchozí nastavení. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.da=Tjek manualen, der fulgte med til din Fibaro-røgsensor, for at få oplysninger om avancerede indstillinger. Hvis du ikke foretager nogen ændringer nedenfor, anvendes standardindstillingerne. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.nl=Bekijk de handleiding die u bij uw Fibaro-rooksensor hebt ontvangen voor informatie over geavanceerde instellingen. Als u hieronder geen wijzigingen invoert, worden de standaardinstellingen gebruikt. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.et=Vaadake oma Fibaro suitsuanduriga kaasasolevat kasutusjuhendit, et saada teavet täpsemate seadete kohta. Kui te ei tee all muudatusi, kasutatakse vaikeseadeid. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.fi=Saat tietoja lisäasetuksista Fibaro-savutunnistimen mukana toimitetusta oppaasta. Jos et tee alla mainittuja muutoksia, käytetään oletusasetuksia. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.fr=Consultez le manuel fourni avec votre détecteur de fumée Fibaro pour plus d'informations sur les paramètres avancés. Si vous n'apportez aucune modification ci-dessous, les paramètres par défaut seront utilisés. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.fr-ca=Consultez le manuel fourni avec votre détecteur de fumée Fibaro pour plus d'informations sur les paramètres avancés. Si vous n'apportez aucune modification ci-dessous, les paramètres par défaut seront utilisés. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.de=In der Bedienungsanleitung Ihres Fibaro-Rauchmelders finden Sie Informationen zu den erweiterten Einstellungen. Wenn Sie unten keine Änderungen vornehmen, werden die Standardeinstellungen verwendet. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.el=Ανατρέξτε στο εγχειρίδιο που συνοδεύει τον αισθητήρα καπνού Fibaro για πληροφορίες σχετικά με τις σύνθετες ρυθμίσεις. Εάν δεν κάνετε αλλαγές παρακάτω, θα χρησιμοποιηθούν οι προεπιλεγμένες ρυθμίσεις. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.iw=עיין במדריך שהגיע עם גלאי העשן של Fibaro לקבלת מידע על הגדרות מתקדמות. אם לא תצבע שום שינויים להלן, המכשיר ישתמש בהגדרות ברירת המחדל. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.hi-in=उन्नत सेटिंग्स के बारे में जानकारी के लिए, अपने Fibaro स्मोक सेंसर के साथ आए मैनुअल की जांच करें। अगर आप नीचे कोई बदलाव नहीं करते हैं, तो डिफॉल्ट सेटिंग्स का उपयोग किया जाएगा। +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.hu=A speciális beállításokról a Fibaro füstérzékelőhöz kapott kézikönyvből tájékozódhat. Ha nem végez módosításokat alább, a rendszer az alapértelmezett értékeket fogja használni. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.is=Lestu handbókina sem fylgdi Fibaro-reykskynjaranum til að fá nánari upplýsingar um ítarlegar stillingar. Ef þú gerir engar breytingar hér að neðan verða sjálfgefnar stillingar notaðar. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.in=Periksa manual yang disertakan dengan Fibaro Smoke Sensor untuk melihat informasi mengenai pengaturan lanjutan. Jika Anda tidak melakukan perubahan di bawah ini, maka pengaturan default akan digunakan. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.it=Per informazioni sulle impostazioni avanzate, controllate il manuale in dotazione con il rilevatore di fumo Fibaro. Se non apportate le modifiche di seguito, verranno applicate le impostazioni predefinite. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.ja=詳細設定については、Fibaro煙センサーに付属のマニュアルをご確認ください。以下の変更を行わないと、初期設定が使用されます。 +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.ko=Fibaro 연기 센서 사용 설명서에서 고급 설정에 관한 정보를 확인할 수 있어요. 아래에서 설정을 변경하지 않으면 기본 설정으로 사용하게 돼요. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.lv=Informāciju par papildu iestatījumiem skatiet Fibaro dūmu sensora rokasgrāmatā. Ja neveiksit nekādas izmaiņas, tiks izmantoti noklusējuma iestatījumi. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.lt=Informacijos apie išplėstinius nustatymus ieškokite prie „Fibaro“ dūmų jutiklio pridėtame vadove. Jei toliau neatliksite jokių pakeitimų, bus naudojami numatytieji nustatymai. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.ms=Semak manual yang datang bersama Penderia Asap Fibaro anda untuk maklumat tentang aturan lanjutan. Jika anda tidak melakukan apa-apa perubahan di bawah, aturan lalai akan digunakan. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.no=Se i håndboken som fulgte med Fibaro Smoke Sensor for informasjon om avanserte innstillinger. Hvis du ikke gjør noen endringer nedenfor, brukes standardinnstillingene. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.pl=Zajrzyj do instrukcji dostarczonej wraz z czujnikiem dymu Fibaro, aby uzyskać informacje na temat ustawień zaawansowanych. Jeśli nie wprowadzisz żadnych zmian, będą używane ustawienia fabryczne. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.pt=Consulte o manual fornecido com o seu Sensor de Fumo Fibaro, para obter informações sobre as definições avançadas. Se não fizer nenhuma alteração em baixo, serão utilizadas as predefinições. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.ro=Consultați manualul care a venit împreună cu senzorul de fum Fibaro pentru a afla informații despre setările avansate. Dacă nu efectuați nicio modificare mai jos, vor fi utilizate setările implicite. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.ru=Информация о расширенных настройках приведена в руководстве, прилагаемом к датчику дыма Fibaro. Если вы не внесете изменения ниже, будут применены настройки по умолчанию. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.sr=Informacije o naprednim podešavanjima potražite u priručniku koji ste dobili uz Fibaro senzor dima. Ako u nastavku ne unesete promene, koristiće se podrazumevana podešavanja. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.sk=Informácie o rozšírených nastaveniach nájdete v návode na použitie senzora dymu Fibaro. Ak nižšie nevykonáte žiadne zmeny, použijú sa predvolené nastavenia. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.sl=Za informacije o dodatnih nastavitvah preverite priročnik, ki je bil priložen senzorju dima Fibaro. Če spodaj ne opravite nobene spremembe, bodo uporabljene privzete nastavitve. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.es=Consulta el manual que viene con el sensor de humo Fibaro para obtener información sobre los ajustes avanzados. Si no realizas ningún cambio a continuación, se usarán los ajustes predeterminados. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.sv=Läs handboken som medföljde Fibaro-brandvarnaren om du vill ha information om avancerade inställningar. Om du inte ändrar något nedan används standardinställningarna. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.th=ตรวจสอบคู่มือที่มาพร้อมกับเซ็นเซอร์ควัน Fibaro ของคุณเพื่อดูข้อมูลเกี่ยวกับการตั้งค่าขั้นสูง หากคุณไม่ดำเนินการเปลี่ยนแปลงใดๆ ด้านล่าง ระบบจะใช้การตั้งค่าเริ่มต้น +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.tr=Gelişmiş ayarlarla ilgili bilgi için Fibaro Duman Sensörünüzle birlikte verilen kılavuzu kontrol edin. Aşağıda herhangi bir değişiklik yapmazsanız varsayılan ayarlar kullanılır. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.uk=Відомості про додаткові налаштування наведено в посібнику датчика диму Fibaro. Якщо ви не внесете жодних змін, буде використано налаштування за замовчуванням. +'''Please consult Fibaro Smoke Sensor operating manual for advanced setting options. You can skip this configuration to use default settings'''.vi=Xem sách hướng dẫn kèm theo Cảm biến khói Fibaro của bạn để biết thêm thông tin về các cài đặt nâng cao. Nếu bạn không thực hiện thay đổi nào dưới đây, cài đặt mặc định sẽ được sử dụng. +'''Notifications'''.en=Notifications +'''Notifications'''.en-gb=Notifications +'''Notifications'''.en-us=Notifications +'''Notifications'''.en-ca=Notifications +'''Notifications'''.en-ph=Notifications +'''Notifications'''.sq=Njoftimet +'''Notifications'''.ar=الإشعارات +'''Notifications'''.be=Апавяшчэнні +'''Notifications'''.sr-ba=Obavještenja +'''Notifications'''.bg=Уведомления +'''Notifications'''.ca=Notificacions +'''Notifications'''.zh-cn=通知 +'''Notifications'''.zh-hk=通知 +'''Notifications'''.zh-tw=通知 +'''Notifications'''.hr=Obavijesti +'''Notifications'''.cs=Oznámení +'''Notifications'''.da=Meddelelser +'''Notifications'''.nl=Meldingen +'''Notifications'''.et=Teavitused +'''Notifications'''.fi=Ilmoitukset +'''Notifications'''.fr=Notifications +'''Notifications'''.fr-ca=Notifications +'''Notifications'''.de=Benachrichtigungen +'''Notifications'''.el=Ειδοποιήσεις +'''Notifications'''.iw=התראות +'''Notifications'''.hi-in=सूचनाएँ +'''Notifications'''.hu=Értesítések +'''Notifications'''.is=Tilkynningar +'''Notifications'''.in=Notifikasi +'''Notifications'''.it=Notifiche +'''Notifications'''.ja=通知 +'''Notifications'''.ko=알림 +'''Notifications'''.lv=Paziņojumi +'''Notifications'''.lt=Pranešimai +'''Notifications'''.ms=Pemberitahuan +'''Notifications'''.no=Varsler +'''Notifications'''.pl=Powiadomienia +'''Notifications'''.pt=Notificações +'''Notifications'''.ro=Notificări +'''Notifications'''.ru=Уведомления +'''Notifications'''.sr=Obaveštenja +'''Notifications'''.sk=Oznámenia +'''Notifications'''.sl=Obvestila +'''Notifications'''.es=Notificaciones +'''Notifications'''.sv=Aviseringar +'''Notifications'''.th=การแจ้งเตือน +'''Notifications'''.tr=Bildirimler +'''Notifications'''.uk=Сповіщення +'''Notifications'''.vi=Thông báo +'''Temperature report hysteresis'''.en=Temperature report hysteresis +'''Temperature report hysteresis'''.en-gb=Temperature report hysteresis +'''Temperature report hysteresis'''.en-us=Temperature report hysteresis +'''Temperature report hysteresis'''.en-ca=Temperature report hysteresis +'''Temperature report hysteresis'''.sq=Histereza e raportit për temperaturën +'''Temperature report hysteresis'''.ar=تخلف تقرير درجة الحرارة +'''Temperature report hysteresis'''.be=Гістэрэзіс справаздач аб тэмпературы +'''Temperature report hysteresis'''.sr-ba=Histereza izvještaja o temperaturi +'''Temperature report hysteresis'''.bg=Хистерезис за отчитане на температурата +'''Temperature report hysteresis'''.ca=Histèresi de l'informe de temperatura +'''Temperature report hysteresis'''.zh-cn=温度报告迟滞 +'''Temperature report hysteresis'''.zh-hk=溫度報告滯後 +'''Temperature report hysteresis'''.zh-tw=溫度報告磁滯 +'''Temperature report hysteresis'''.hr=Histereza izvješća o temperaturi +'''Temperature report hysteresis'''.cs=Hystereze hlášení teploty +'''Temperature report hysteresis'''.da=Hysterese for temperaturrapport +'''Temperature report hysteresis'''.nl=Hysterese temperatuurrapport +'''Temperature report hysteresis'''.et=Temperatuurist teavitamise hüsterees +'''Temperature report hysteresis'''.fi=Lämpötilaraportin hystereesi +'''Temperature report hysteresis'''.fr=Hystérèse du rapport de température +'''Temperature report hysteresis'''.fr-ca=Hystérèse du rapport de température +'''Temperature report hysteresis'''.de=Temperaturberichtshysterese +'''Temperature report hysteresis'''.el=Υστέρηση αναφοράς θερμοκρασίας +'''Temperature report hysteresis'''.iw=חשל דוח טמפרטורה +'''Temperature report hysteresis'''.hi-in=तापमान रिपोर्ट हिस्टैरिसीस +'''Temperature report hysteresis'''.hu=Hőmérsékleti jelentési hiszterézise +'''Temperature report hysteresis'''.is=Segulheldni hitastigsskráninga +'''Temperature report hysteresis'''.in=Histeresis laporan suhu +'''Temperature report hysteresis'''.it=Isteresi report sulla temperatura +'''Temperature report hysteresis'''.ja=温度レポートヒステリシス +'''Temperature report hysteresis'''.ko=온도 알림 이력 현상 +'''Temperature report hysteresis'''.lv=Temperatūras ziņojuma histerēze +'''Temperature report hysteresis'''.lt=Temperatūros pranešimo histerezė +'''Temperature report hysteresis'''.ms=Histeresis laporan suhu +'''Temperature report hysteresis'''.no=Temperaturrapporthysterese +'''Temperature report hysteresis'''.pl=Histereza raportów o temperaturze +'''Temperature report hysteresis'''.pt=Histerese do relatório de temperatura +'''Temperature report hysteresis'''.ro=Histerezis raportare temperatură +'''Temperature report hysteresis'''.ru=Задержка отчета о температуре +'''Temperature report hysteresis'''.sr=Histereza izveštaja o temperaturi +'''Temperature report hysteresis'''.sk=Hysteréza hlásenia teploty +'''Temperature report hysteresis'''.sl=Histereza poročil o temperaturi +'''Temperature report hysteresis'''.es=Histéresis de informe de temperatura +'''Temperature report hysteresis'''.sv=Hysteres för temperaturrapport +'''Temperature report hysteresis'''.th=ฮิสเทอรีซิสของรายงานอุณหภูมิ +'''Temperature report hysteresis'''.tr=Sıcaklık raporlama gecikmesi +'''Temperature report hysteresis'''.uk=Час надсилання сповіщень про температуру +'''Temperature report hysteresis'''.vi=Độ trễ báo cáo nhiệt độ +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.en=Press and hold the B button for at least 3 seconds. When the indicator glows white, release the B button. The indicator will start changing colours in sequence. Press the B button when the indicator turns green. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.en-gb=Press and hold the B button for at least 3 seconds. When the indicator glows white, release the B button. The indicator will start changing colours in sequence. Press the B button when the indicator turns green. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.en-us=Press and hold the B button for at least 3 seconds. When the indicator glows white, release the B button. The indicator will start changing colors in sequence. Press the B button when the indicator turns green. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.en-ca=Press and hold the B button for at least 3 seconds. When the indicator glows white, release the B button. The indicator will start changing colours in sequence. Press the B button when the indicator turns green. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.sq=Shtyp dhe mbaj butonin B për së paku 3 sekonda. Kur treguesi të ndizet i bardhë, liroje butonin B. Treguesi do të fillojë të ndryshojë ngjyrat në sekuencë. Shtyp butonin B kur treguesi të bëhet i gjelbër. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.ar=اضغط مع الاستمرار على الزر B لمدة ۳ ثوانٍ على الأقل. عندما يضيء المؤشر باللون الأبيض، قم بتحرير الزر B. سيبدأ تغيير ألوان المؤشر بالتتابع. اضغط على الزر B عندما يتحول لون المؤشر إلى الأخضر. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.be=Націсніце кнопку B і ўтрымлівайце яе мінімум 3 секунды. Калі індыкатар засвеціцца белым, адпусціце кнопку B. Колеры індыкатара пачнуць мяняцца ў пэўнай паслядоўнасці. Націсніце кнопку B, калі колер індыкатара зробіцца зялёным. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.sr-ba=Pritisnite i zadržite dugme B najmanje tri sekunde. Kada indikator zasvijetli bijelom bojom, otpustite dugme B. Indikator će uzastopno početi mijenjati boje. Pritisnite dugme B kada indikator postane zelen. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.bg=Натиснете и задръжте бутона B за поне 3 секунди. Когато индикаторът свети бяло, пуснете бутона B. Индикаторът ще започне да променя цветовете последователно. Натиснете бутона B, когато индикаторът стане зелен. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.ca=Mantén premut el botó B almenys 3 segons. Quan l'indicador brilli amb el colo blanc, deixa anar al botó B. L'indicador començarà a canviar de color en seqüència. Prem el botó B quan l'indicador es torni verd. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.zh-cn=长按 B 按钮至少 3 秒钟。当指示灯呈白色亮起时,松开 B 按钮。指示灯将开始按顺序更改颜色。指示灯变为绿色时,按 B 按钮。 +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.zh-hk=按住 B 按鍵至少 3 秒。當指示燈發出白光時,鬆開 B 按鍵。指示燈將依次變更顏色。當指示燈變成綠色時,按下 B 按鍵。 +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.zh-tw=請長按 B 按鈕至少 3 秒。指示燈亮白色時,放開 B 按鈕。指示燈色彩隨即會依序變化。指示燈轉為綠色時,請按下 B 按鈕。 +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.hr=Pritisnite i držite gumb B najmanje 3 sekunde. Kada pokazatelj zasvijetli bijelom bojom, otpustite gumb B. Pokazatelj će početi uzastopno mijenjati boje. Pritisnite gumb B kada pokazatelj pozeleni. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.cs=Stiskněte a podržte tlačítko B alespoň na 3 sekundy. Když indikátor svítí bíle, pusťte tlačítko B. Indikátor začne postupně měnit barvy. Až začne indikátor svítit zeleně, pusťte tlačítko B. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.da=Tryk og hold på B-knappen i mindst 3 sekunder. Når indikatoren lyser hvidt, skal du slippe B-knappen. Indikatoren begynder at skifte farve i sekvens. Tryk på B-knappen, når indikatoren bliver grøn. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.nl=Houd de knop B tenminste 3 seconden ingedrukt. Laat de knop B los als de indicator wit begint te branden. De indicator verandert in volgorde van kleur. Druk op de knop B als de indicator groen wordt. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.et=Vajutage ja hoidke nuppu B vähemalt 3 sekundit. Kui indikaator põleb valgelt, vabastage nupp B. Indikaator hakkab järgemööda värve muutma. Vajutage nuppu B, kui indikaator põleb roheliselt. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.fi=Pidä B-painiketta painettuna vähintään 3 sekunnin ajan. Vapauta B-painike, kun ilmaisin palaa valkoisena. Ilmaisin alkaa vaihtaa väriä järjestyksessä. Paina B-painiketta, kun ilmaisin muuttuu vihreäksi. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.fr=Maintenez le bouton B appuyé pendant au moins 3 secondes. Lorsque l'indicateur s'allume en blanc, relâchez le bouton B. L'indicateur commencera à changer de couleur progressivement. Appuyez sur le bouton B lorsque l'indicateur passe au vert. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.fr-ca=Pressez le bouton B pendant au moins 3 secondes. Lorsque l'indicateur s'allume en blanc, relâchez le bouton B. L'indicateur commencera à changer de couleur progressivement. Pressez le bouton B lorsque l'indicateur passe au vert. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.de=Halten Sie die B-Taste mindestens 3 Sekunden gedrückt. Wenn die Anzeige weiß leuchtet, lassen Sie die B-Taste los. Die Anzeige ändert die Farbe der Reihe nach. Drücken Sie die B-Taste, wenn die Anzeige grün leuchtet. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.el=Πιέστε παρατεταμένα το κουμπί B για τουλάχιστον 3 δευτερόλεπτα. Όταν η ένδειξη ανάψει με λευκό χρώμα, αποδεσμεύστε το κουμπί B. Η ένδειξη θα αρχίσει να αλλάζει χρώματα διαδοχικά. Πιέστε το κουμπί B μόλις η ένδειξη γίνει πράσινη. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.iw=לחץ על הלחצן B והחזק לפחות 3 שניות. כשהמחוון זוהר בלבן, שחרר את לחצן B. המחוון יתחיל לשנות צבעים ברצף. לחץ על הלחצן B כשהמחוון נעשה ירוק. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.hi-in=B बटन को कम से कम 3 सेकंड तक दबाकर रखें। जब संकेतक सफेद चमकने लगे, तो B बटन को छोड़ दें। संकेतक क्रम में रंग बदलना प्रारंभ कर देगा। जब संकेतक हरा हो जाए, तो B बटन दबाएँ। +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.hu=Tartsa nyomva a B gombot legalább 3 másodpercig. Amikor a jelzőfény fehérre vált, engedje el a B gombot. A jelzőfény sorban színt vált. Nyomja meg a B gombot, amikor a jelzőfény zöldre vált. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.is=Haltu B-hnappinum inni í minnst 3 sekúndur. Þegar gaumljósið logar í hvítu skaltu sleppa B-hnappinum. Liturinn á gaumljósinu byrjar að breytast í tiltekinni röð. Ýttu á B-hnappinn þegar ljósið verður grænt. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.in=Tekan dan tahan tombol B minimal 3 detik. Saat indikator menyala berwarna putih, lepaskan tombol B. Indikator akan mulai berubah warna secara berurutan. Tekan tombol B saat indikator berwarna hijau. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.it=Tenete premuto il pulsante B per almeno 3 secondi. Quando lʹindicatore lampeggia con luce bianca, rilasciate il pulsante B. Lʹindicatore inizierà a cambiare colore in sequenza. Quando diventa verde, premete il pulsante B. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.ja=Bボタンを3秒以上長押ししてください。インジケーターが白く光ったら、Bボタンを離してください。インジケーターの色が順に変化します。インジケーターが緑になったら、Bボタンを離してください。 +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.ko=3초 이상 B 버튼을 길게 누르세요. 표시등이 흰색으로 반짝이면 B 버튼에서 손을 떼세요. 표시등의 색상이 순서대로 바뀌다가 초록색이 켜지면 B 버튼을 누르세요. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.lv=Nospiediet un vismaz 3 sekundes turiet pogu B. Kad indikators iedegas baltā krāsā, atlaidiet pogu B. Indikators sāks mainīt krāsas pēc kārtas. Kad indikators kļūst zaļš, nospiediet pogu B. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.lt=Paspauskite ir bent 3 sek. palaikykite mygtuką B. Kai indikatorius pradės šviesti baltai, mygtuką B atleiskite. Indikatoriaus spalvos keisis paeiliui. Kai indikatorius švies žaliai, paspauskite mygtuką B. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.ms=Tekan dan tahan butang B untuk sekurang-kurangnya 3 saat. Apabila penunjuk bercahaya putih, lepaskan butang B. Penunjuk akan mula berubah warna mengikut turutan. Tekan butang B apabila penunjuk bertukar hijau. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.no=Trykk på og hold B-knappen i minst 3 sekunder. Når indikatoren lyser hvitt, slipper du B-knappen. Indikatoren begynner å endre farge i rekkefølge. Trykk på B-knappen når indikatoren lyser grønt. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.pl=Naciśnij przycisk B i przytrzymaj go co najmniej 3 sekundy. Gdy wskaźnik zaświeci na biało, zwolnij przycisk B. Wskaźnik zacznie zmieniać kolor. Naciśnij przycisk B, kiedy wskaźnik będzie zielony. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.pt=Prima sem soltar o botão B durante pelo menos 3 segundos. Quando o indicador brilhar a branco, solte o botão B. O indicador começará a mudar de cor em sequência. Prima o botão B quando o indicador ficar verde. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.ro=Mențineți apăsat butonul B timp de cel puțin 3 secunde. Atunci când indicatorul se aprinde în culoarea albă, eliberați butonul B. Indicatorul va începe să schimbe culorile secvențial. Apăsați butonul B atunci când indicatorul devine verde. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.ru=Нажмите и удерживайте кнопку B не менее 3 секунд. Когда индикатор загорится белым, отпустите кнопку. Индикатор начнет последовательно менять цвета. Нажмите кнопку B, когда индикатор загорится зеленым. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.sr=Pritisnite i zadržite dugme B na najmanje 3 sekunde. Kada lampica zasvetli belom bojom, otpustite dugme B. Lampica će početi da menja boje redom. Pritisnite dugme B kada lampica postane zelena. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.sk=Stlačte tlačidlo B a podržte ho stlačené aspoň na 3 sekundy. Keď sa indikátor rozsvieti na bielo, uvoľnite tlačidlo B. Indikátor začne postupne meniť farby. Keď sa indikátor zmení na zelený, stlačte tlačidlo B. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.sl=Pritisnite in vsaj 3 sekunde držite gumb B. Ko indikator zasveti belo, spustite gumb B. Indikator bo začel spreminjati barve v zaporedju. Ko indikator zasveti zeleno, pritisnite gumb B. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.es=Mantén pulsado el botón B durante al menos 3 segundos. Cuando el indicador brille de color blanco, suelta el botón B. El indicador empezará a cambiar de color en una secuencia. Pulsa el botón B cuando el indicador cambie a verde. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.sv=Håll ned B-knappen i minst tre sekunder. Släpp upp den när indikatorn blir vit. Indikatorns färg ändras i en följd. Tryck på B-knappen när indikatorn blir grön. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.th=กดค้างที่ปุ่ม B นานอย่างน้อย 3 วินาที เมื่อตัวระบุติดสว่างเป็นสีขาว ให้ปล่อยปุ่ม B ตัวระบุจะเริ่มเปลี่ยนสีตามลำดับ กดปุ่ม B เมื่อตัวระบุเปลี่ยนเป็นสีเขียว +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.tr=B tuşunu en az 3 saniye basılı tutun. Gösterge beyaz renkte yandığında, B tuşunu bırakın. Gösterge sırayla farklı renklerde yanmaya başlar. Gösterge yeşil renkte yandığında B tuşuna basın. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.uk=Утримуйте кнопку B принаймні 3 секунди та відпустіть її, коли індикатор почне світитися білим. Після цього індикатор послідовно змінюватиме кольори. Натисніть кнопку B, коли колір індикатора стане зеленим. +'''Enter the menu by press and hold B-button for 3 seconds. Once indicator glows WHITE, release the B-button. Visual indicator will start changing colours in sequence. Press B-button briefly when visual indicator glows GREEN'''.vi=Nhấn và giữ phím B trong ít nhất 3 giây. Khi chỉ báo hiện màu trắng, hãy thả phím B. Chỉ báo sẽ bắt đầu lần lượt thay đổi màu. Hãy nhấn phím B khi chỉ báo chuyển màu xanh lá. +'''Casing opened'''.en=Case opened +'''Casing opened'''.en-gb=Case opened +'''Casing opened'''.en-us=Case opened +'''Casing opened'''.en-ca=Case opened +'''Casing opened'''.sq=Kutia hapur +'''Casing opened'''.ar=تم فتح الحالة +'''Casing opened'''.be=Корпус адчынены +'''Casing opened'''.sr-ba=Omot je otvoren +'''Casing opened'''.bg=Кутията е отворена +'''Casing opened'''.ca=S'ha obert la funda +'''Casing opened'''.zh-cn=充电盒已打开 +'''Casing opened'''.zh-hk=已打開外殼 +'''Casing opened'''.zh-tw=開蓋 +'''Casing opened'''.hr=Poklopac otvoren +'''Casing opened'''.cs=Pouzdro otevřeno +'''Casing opened'''.da=Kabinet åbnet +'''Casing opened'''.nl=Hoes geopend +'''Casing opened'''.et=Ümbris avatud +'''Casing opened'''.fi=Kotelo avattu +'''Casing opened'''.fr=Boîtier ouvert +'''Casing opened'''.fr-ca=Boitier ouvert +'''Casing opened'''.de=Gehäuse geöffnet +'''Casing opened'''.el=Άνοιξε υπόθεση +'''Casing opened'''.iw=הנרתיק פתוח +'''Casing opened'''.hi-in=केस खुल गया +'''Casing opened'''.hu=Ház kinyitva +'''Casing opened'''.is=Hulstur opnað +'''Casing opened'''.in=Casing dibuka +'''Casing opened'''.it=Case aperto +'''Casing opened'''.ja=ケースが開いている +'''Casing opened'''.ko=케이스 열림 +'''Casing opened'''.lv=Atvērts vāks +'''Casing opened'''.lt=Dėklas atidarytas +'''Casing opened'''.ms=Bekas dibuka +'''Casing opened'''.no=Deksel åpnet +'''Casing opened'''.pl=Obudowa otwarta +'''Casing opened'''.pt=Caixa aberta +'''Casing opened'''.ro=Carcasă deschisă +'''Casing opened'''.ru=Корпус открыт +'''Casing opened'''.sr=Slučaj je otvoren +'''Casing opened'''.sk=Puzdro otvorené +'''Casing opened'''.sl=Ohišje je odprto +'''Casing opened'''.es=Cubierta abierta +'''Casing opened'''.sv=Höljet har öppnats +'''Casing opened'''.th=เปิดฝาปิดแล้ว +'''Casing opened'''.tr=Muhafaza açıldı +'''Casing opened'''.uk=Корпус відкрито +'''Casing opened'''.vi=Đã mở nắp +'''Reports inactive'''.en=No reports +'''Reports inactive'''.en-gb=No reports +'''Reports inactive'''.en-us=No reports +'''Reports inactive'''.en-ca=No reports +'''Reports inactive'''.sq=Nuk ka raporte +'''Reports inactive'''.ar=لا توجد تقارير +'''Reports inactive'''.be=Няма справаздач +'''Reports inactive'''.sr-ba=Nema izvještaja +'''Reports inactive'''.bg=Няма отчети +'''Reports inactive'''.ca=Sense informes +'''Reports inactive'''.zh-cn=没有报告 +'''Reports inactive'''.zh-hk=無報告 +'''Reports inactive'''.zh-tw=無報告 +'''Reports inactive'''.hr=Nema izvješća +'''Reports inactive'''.cs=Žádné zprávy +'''Reports inactive'''.da=Ingen rapporter +'''Reports inactive'''.nl=Geen rapporten +'''Reports inactive'''.et=Aruandeid pole +'''Reports inactive'''.fi=Raportteja ei ole +'''Reports inactive'''.fr=Aucun rapport +'''Reports inactive'''.fr-ca=Aucun rapport +'''Reports inactive'''.de=Keine Berichte +'''Reports inactive'''.el=Δεν υπάρχουν αναφορές +'''Reports inactive'''.iw=אין דוחות +'''Reports inactive'''.hi-in=कोई रिपोर्ट्स नहीं +'''Reports inactive'''.hu=Nincsenek jelentések +'''Reports inactive'''.is=Engar skýrslur +'''Reports inactive'''.in=Tidak ada laporan +'''Reports inactive'''.it=Nessun report +'''Reports inactive'''.ja=レポートなし +'''Reports inactive'''.ko=알림 받지 않음 +'''Reports inactive'''.lv=Nav ziņojumu +'''Reports inactive'''.lt=Ataskaitų nėra +'''Reports inactive'''.ms=Tiada laporan +'''Reports inactive'''.no=Ingen rapporter +'''Reports inactive'''.pl=Brak raportów +'''Reports inactive'''.pt=Sem relatórios +'''Reports inactive'''.ro=Niciun raport +'''Reports inactive'''.ru=Нет отчетов +'''Reports inactive'''.sr=Nema izveštaja +'''Reports inactive'''.sk=Žiadne správy +'''Reports inactive'''.sl=Ni poročil +'''Reports inactive'''.es=No hay informes +'''Reports inactive'''.sv=Inga rapporter +'''Reports inactive'''.th=ไม่มีรายงาน +'''Reports inactive'''.tr=Rapor yok +'''Reports inactive'''.uk=Немає сповіщень +'''Reports inactive'''.vi=Không có báo cáo +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.en=After installing, press the B button on your Fibaro Smoke Sensor to update the device's status and configuration. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.en-gb=After installing, press the B button on your Fibaro Smoke Sensor to update the device's status and configuration. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.en-us=After installing, press the B button on your Fibaro Smoke Sensor to update the device's status and configuration. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.en-ca=After installing, press the B button on your Fibaro Smoke Sensor to update the device's status and configuration. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.sq=Pas instalimit, shtyp butonin B te Sensori i tymit Fibaro për të përditësuar statusin dhe konfigurimin e pajisjes. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.ar=بعد التثبيت، اضغط على الزر B على مستشعر الدخان Fibaro الخاص بك لتحديث حالة الجهاز والإعداد. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.be=Пасля ўсталявання націсніце кнопку B на датчыку дыму Fibaro, каб абнавіць стан і канфігурацыю прылады. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.sr-ba=Nakon instalacije pritisnite dugme B na senzoru dima kompanije Fibaro za ažuriranje statusa i konfiguraciju uređaja. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.bg=След инсталирането натиснете бутона B върху сензора за дим Fibaro, за да актуализирате състоянието и конфигурацията на устройството. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.ca=Després de la instal·lació, prem el botó B del sensor de fum Fibaro per actualitzar l'estat i la configuració del dispositiu. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.zh-cn=安装后,按 Fibaro 烟雾传感器上的 B 按钮来更新设备的状态和配置。 +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.zh-hk=安裝後,請按下 Fibaro 煙霧偵測器上的 B 按鍵以更新裝置的狀態與配置。 +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.zh-tw=安裝後,請按下 Fibaro 煙霧偵測器上的 B 按鈕來更新裝置狀態與設定。 +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.hr=Nakon instalacije pritisnite gumb B na senzoru dima tvrtke Fibaro za aktualizaciju statusa i konfiguracije uređaja. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.cs=Po nainstalování stiskněte tlačítko B na detektoru kouře Fibaro, abyste aktualizovali stav a konfiguraci zařízení. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.da=Efter installationen skal du trykke på B-knappen på din Fibaro-røgsensor for at opdatere enhedens status og konfiguration. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.nl=Druk na installeren op de knop B op uw Fibaro-rooksensor om de status en configuratie van het apparaat bij te werken. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.et=Vajutage oma Fibaro suitsuanduril pärast installimist nuppu B, et värskendada seadme olekut ja konfiguratsiooni. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.fi=Päivitä laitteen tila ja kokoonpano painamalla Fibaro-savutunnistimen B-painiketta asennuksen jälkeen. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.fr=Après l'installation, appuyez sur le bouton B de votre détecteur de fumée Fibaro pour mettre à jour le statut et la configuration de l'appareil. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.fr-ca=Après l'installation, pressez le bouton B de votre détecteur de fumée Fibaro pour mettre à jour le statut et la configuration de l'appareil. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.de=Drücken Sie nach der Installation auf die B-Taste Ihres Fibaro-Rauchmelders, um den Status und die Konfiguration des Geräts zu aktualisieren. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.el=Μετά την εγκατάσταση, πιέστε το κουμπί B στον αισθητήρα καπνού Fibaro για να ενημερώσετε την κατάσταση και τη διαμόρφωση της συσκευής. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.iw=לאחר ההתקנה, לחץ על המקש B על חיישן העשן של Fibaro כדי לעדכן את הסטטוס והתצורה של המכשיר. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.hi-in=स्थापित करने के बाद, डिवाइस की स्थिति और कॉन्फिगरेशन अपडेट करने के लिए अपने Fibaro स्मोक सेंसर पर B बटन दबाएँ। +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.hu=A telepítés után nyomja meg a B gombot a Fibaro füstérzékelőn az eszköz állapotának és konfigurációjának frissítéséhez. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.is=Eftir uppsetningu skaltu ýta á B-hnappinn á Fibaro-reykskynjaranum þínum til að uppfæra stöðu og grunnstillingar tækisins. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.in=Setelah menginstal, tekan tombol B di Fibaro Smoke Sensor untuk memperbarui status dan konfigurasi perangkat. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.it=Dopo lʹinstallazione, premete il pulsante B sul sensore di fumo Fibaro per aggiornare lo stato e la configurazione del dispositivo. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.ja=設置した後、Fibaro煙センサーのBボタンを押してデバイスのステータスと設定を更新してください。 +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.ko=설치한 후에 Fibaro 연기 센서의 B 버튼을 누르면 디바이스 상태 및 설정이 업데이트돼요. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.lv=Pēc instalēšanas nospiediet Fibaro dūmu sensora pogu B, lai atjauninātu ierīces statusu un konfigurāciju. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.lt=Įdiegę paspauskite ƒ„Fibaro“ dūmų jutiklio mygtuką B, kad atnaujintumėte įrenginio būseną ir konfigūraciją. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.ms=Selepas pemasangan, tekan butang B pada Penderia Asap Fibaro anda untuk mengemas kini status dan penatarajahan peranti. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.no=Etter installasjon trykker du på B-knappen på Fibaro Smoke Sensor for å oppdatere enhetens status og konfigurasjon. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.pl=Po zakończeniu instalacji naciśnij przycisk B na czujniku dymu Fibaro, aby zaktualizować stan i konfigurację urządzenia. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.pt=Após a instalação, prima o botão B do seu Sensor de Fumo Fibaro para actualizar o estado e a configuração do dispositivo. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.ro=După instalare, apăsați butonul B de pe senzorul de fum Fibaro pentru a actualiza starea și configurația dispozitivului. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.ru=После установки нажмите кнопку B на датчике дыма Fibaro, чтобы обновить статус и конфигурацию устройства. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.sr=Nakon instaliranja pritisnite dugme B na FIbaro senzoru za dim kako biste ažurirali status i konfiguraciju uređaja. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.sk=Po nainštalovaní stlačte tlačidlo B na senzore dymu Fibaro, aby sa aktualizoval stav a konfigurácia zariadenia. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.sl=Po namestitvi pritisnite gumb B na senzorju dima Fibaro, da posodobite stanje in konfiguracijo naprave. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.es=Una vez instalado, pulsa el botón B en tu sensor de humo Fibaro para actualizar el estado y la configuración del dispositivo. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.sv=Tryck efter installationen på B-knappen på din Fibaro-brandvarnare för att uppdatera enhetens status och konfiguration. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.th=หลังการติดตั้ง ให้กดปุ่ม B บนเซ็นเซอร์ควัน Fibaro ของคุณเพื่ออัพเดทสถานะและการกำหนดค่าของอุปกรณ์ +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.tr=Yükleme işleminden sonra, cihazın durumunu ve yapılandırmasını güncellemek için Fibaro Duman Sensörünüzde B tuşuna basın. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.uk=Після встановлення натисніть кнопку B на датчику диму Fibaro, щоб оновити стан і конфігурацію пристрою. +'''After successful installation, please click B-button at the Fibaro Smoke Sensor to update device status and configuration'''.vi=Sau khi cài đặt, nhấn phím B trên Cảm biến khói Fibaro của bạn để cập nhật trạng thái và cấu hình của thiết bị. +'''1 hour'''.en=1 hour +'''1 hour'''.en-gb=1 hour +'''1 hour'''.en-us=1 hour +'''1 hour'''.en-ca=1 hour +'''1 hour'''.en-ph=1 hour +'''1 hour'''.sq=1 orë +'''1 hour'''.ar=ساعة واحدة +'''1 hour'''.be=1 гадзіна +'''1 hour'''.sr-ba=Jedan sat +'''1 hour'''.bg=1 час +'''1 hour'''.ca=1 hora +'''1 hour'''.zh-cn=1 小时 +'''1 hour'''.zh-hk=1 小時 +'''1 hour'''.zh-tw=1 小時 +'''1 hour'''.hr=1 sat +'''1 hour'''.cs=1 hodina +'''1 hour'''.da=1 time +'''1 hour'''.nl=1 uur +'''1 hour'''.et=1 tund +'''1 hour'''.fi=1 tunti +'''1 hour'''.fr=1 heure +'''1 hour'''.fr-ca=1 heure +'''1 hour'''.de=1 Stunde +'''1 hour'''.el=1 ώρα +'''1 hour'''.iw=שעה אחת +'''1 hour'''.hi-in=1 घंटा +'''1 hour'''.hu=1 óra +'''1 hour'''.is=1 klukkustund +'''1 hour'''.in=1 jam +'''1 hour'''.it=1 ora +'''1 hour'''.ja=1時間 +'''1 hour'''.ko=1시간 +'''1 hour'''.lv=1 stunda +'''1 hour'''.lt=1 val. +'''1 hour'''.ms=1 jam +'''1 hour'''.no=1 time +'''1 hour'''.pl=1 godzina +'''1 hour'''.pt=1 hora +'''1 hour'''.ro=1 oră +'''1 hour'''.ru=1 час +'''1 hour'''.sr=Jedan sat +'''1 hour'''.sk=1 hodina +'''1 hour'''.sl=1 h +'''1 hour'''.es=1 hora +'''1 hour'''.sv=En timme +'''1 hour'''.th=1 ชั่วโมง +'''1 hour'''.tr=1 saat +'''1 hour'''.uk=1 година +'''1 hour'''.vi=1 giờ +'''Visual indicator notifications status'''.en=Visual indicator notifications +'''Visual indicator notifications status'''.en-gb=Visual indicator notifications +'''Visual indicator notifications status'''.en-us=Visual indicator notifications +'''Visual indicator notifications status'''.en-ca=Visual indicator notifications +'''Visual indicator notifications status'''.sq=Njoftime me tregues vizual +'''Visual indicator notifications status'''.ar=إشعارات المؤشر المرئي +'''Visual indicator notifications status'''.be=Візуальныя апавяшчэнні індыкатара +'''Visual indicator notifications status'''.sr-ba=Obavještenja vizuelnog indikatora +'''Visual indicator notifications status'''.bg=Уведомления чрез визуални индикатори +'''Visual indicator notifications status'''.ca=Notificacions d'indicador visual +'''Visual indicator notifications status'''.zh-cn=视觉指示器通知 +'''Visual indicator notifications status'''.zh-hk=視覺指示燈通知 +'''Visual indicator notifications status'''.zh-tw=視覺顯示通知 +'''Visual indicator notifications status'''.hr=Obavijesti vizualnog pokazatelja +'''Visual indicator notifications status'''.cs=Vizuální indikátor oznámení +'''Visual indicator notifications status'''.da=Visuelle indikatormeddelelser +'''Visual indicator notifications status'''.nl=Meldingen visuele indicator +'''Visual indicator notifications status'''.et=Visuaalse indikaatori teavitused +'''Visual indicator notifications status'''.fi=Visuaalisen ilmaisimen ilmoitukset +'''Visual indicator notifications status'''.fr=Notifications par indicateur visuel +'''Visual indicator notifications status'''.fr-ca=Notifications par indicateur visuel +'''Visual indicator notifications status'''.de=Optische Anzeigebenachrichtigungen +'''Visual indicator notifications status'''.el=Ειδοποιήσεις οπτικής ένδειξης +'''Visual indicator notifications status'''.iw=התראות מחוון חזותי +'''Visual indicator notifications status'''.hi-in=विजुअल संकेतक सूचनाएँ +'''Visual indicator notifications status'''.hu=Vizuális értesítések +'''Visual indicator notifications status'''.is=Sjónrænar tilkynningar +'''Visual indicator notifications status'''.in=Notifikasi indikator visual +'''Visual indicator notifications status'''.it=Indicatore notifiche visive +'''Visual indicator notifications status'''.ja=ビジュアルインジケーター通知 +'''Visual indicator notifications status'''.ko=시각적 표시 알림 +'''Visual indicator notifications status'''.lv=Vizuālie indikatora ziņojumi +'''Visual indicator notifications status'''.lt=Vaizdo indikatoriaus pranešimai +'''Visual indicator notifications status'''.ms=Pemberitahuan penunjuk visual +'''Visual indicator notifications status'''.no=Visuelle indikatorvarsler +'''Visual indicator notifications status'''.pl=Powiadomienia wizualne +'''Visual indicator notifications status'''.pt=Notificações de indicador visual +'''Visual indicator notifications status'''.ro=Notificări indicator vizual +'''Visual indicator notifications status'''.ru=Уведомления визуального индикатора +'''Visual indicator notifications status'''.sr=Vizuelna indikatorska obaveštenja +'''Visual indicator notifications status'''.sk=Vizuálne indikačné oznámenia +'''Visual indicator notifications status'''.sl=Obvestila vidnega indikatorja +'''Visual indicator notifications status'''.es=Notificaciones de indicador visual +'''Visual indicator notifications status'''.sv=Visuella indikatoraviseringar +'''Visual indicator notifications status'''.th=การแจ้งเตือนตัวระบุการมองเห็น +'''Visual indicator notifications status'''.tr=Görsel gösterge bildirimleri +'''Visual indicator notifications status'''.uk=Візуальні сповіщення на індикаторі +'''Visual indicator notifications status'''.vi=Thông báo chỉ báo trực quan +'''All'''.en=All +'''All'''.en-gb=All +'''All'''.en-us=All +'''All'''.en-ca=All +'''All'''.en-ph=All +'''All'''.sq=Të gjitha +'''All'''.ar=الكل +'''All'''.be=Усе +'''All'''.sr-ba=Sve +'''All'''.bg=Всички +'''All'''.ca=Tot +'''All'''.zh-cn=全部 +'''All'''.zh-hk=全部 +'''All'''.zh-tw=全部 +'''All'''.hr=Sve +'''All'''.cs=Vše +'''All'''.da=Alt +'''All'''.nl=Alle +'''All'''.et=Kõik +'''All'''.fi=Kaikki +'''All'''.fr=Tout +'''All'''.fr-ca=Tout +'''All'''.de=Alle +'''All'''.el=Όλα +'''All'''.iw=הכל +'''All'''.hi-in=सभी +'''All'''.hu=Mind +'''All'''.is=Allt +'''All'''.in=Semua +'''All'''.it=Tutti/e +'''All'''.ja=全て +'''All'''.ko=전체 +'''All'''.lv=Visi +'''All'''.lt=Visi +'''All'''.ms=Semua +'''All'''.no=Alle +'''All'''.pl=Wszystkie +'''All'''.pt=Todas +'''All'''.ro=Toate +'''All'''.ru=Все +'''All'''.sr=Sve +'''All'''.sk=Všetky +'''All'''.sl=Vse +'''All'''.es=Todo +'''All'''.sv=Allt +'''All'''.th=ทั้งหมด +'''All'''.tr=Tümü +'''All'''.uk=Усі +'''All'''.vi=Tất cả +# End of Device Preferences diff --git a/devicetypes/smartthings/fidure-thermostat.src/fidure-thermostat.groovy b/devicetypes/smartthings/fidure-thermostat.src/fidure-thermostat.groovy index b644c144b2b..338ebcb6337 100644 --- a/devicetypes/smartthings/fidure-thermostat.src/fidure-thermostat.groovy +++ b/devicetypes/smartthings/fidure-thermostat.src/fidure-thermostat.groovy @@ -43,8 +43,8 @@ metadata { attribute "thermostatOperatingState", "string" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0201,0204,0B05", outClusters: "000A, 0019" - fingerprint manufacturer: "Fidure", model: "A1732R3" // same clusters as above + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0201,0204,0B05", outClusters: "000A, 0019", deviceJoinName: "Fidure Thermostat" + fingerprint manufacturer: "Fidure", model: "A1732R3" , deviceJoinName: "Fidure Thermostat"// same clusters as above } @@ -519,7 +519,7 @@ def checkLastTimeSync(delay) { long duration = (new Date()).getTime() - (new Date(lastSync)).getTime() - // log.debug "check Time: $lastSync duration: ${duration} settings.sync_clock: ${settings.sync_clock}" + //log.debug "check Time: $lastSync duration: ${duration} settings.sync_clock: ${settings.sync_clock}" if (duration > 86400000) { sendEvent("name":"lastTimeSync", "value":"${new Date()}") return setThermostatTime() diff --git a/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy b/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy index 2fa8cb7788e..6b91427a1d9 100644 --- a/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy +++ b/devicetypes/smartthings/fortrezz-water-valve.src/fortrezz-water-valve.groovy @@ -19,8 +19,8 @@ metadata { capability "Refresh" capability "Sensor" - fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70" - fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve" + fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70", deviceJoinName: "FortrezZ Valve" + fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Valve" //FortrezZ Water Valve } // simulator metadata diff --git a/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy b/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy index 394a93de502..a8ea17d7e62 100644 --- a/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy +++ b/devicetypes/smartthings/ge-link-bulb.src/ge-link-bulb.groovy @@ -53,9 +53,9 @@ metadata { capability "Polling" capability "Light" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE_Appliances", model: "ZLL Light", deviceJoinName: "GE Link Bulb" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "SoftWhite", deviceJoinName: "GE Link Soft White Bulb" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "Daylight", deviceJoinName: "GE Link Daylight Bulb" + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE_Appliances", model: "ZLL Light", deviceJoinName: "GE Light" //GE Link Bulb + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "SoftWhite", deviceJoinName: "GE Light" //GE Link Soft White Bulb + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0019", manufacturer: "GE", model: "Daylight", deviceJoinName: "GE Light" //GE Link Daylight Bulb } // UI tile definitions diff --git a/devicetypes/smartthings/glentronics-connection-module.src/glentronics-connection-module.groovy b/devicetypes/smartthings/glentronics-connection-module.src/glentronics-connection-module.groovy index a9cb71e448f..8f201d57700 100644 --- a/devicetypes/smartthings/glentronics-connection-module.src/glentronics-connection-module.groovy +++ b/devicetypes/smartthings/glentronics-connection-module.src/glentronics-connection-module.groovy @@ -20,7 +20,7 @@ metadata { capability "Power Source" capability "Health Check" - fingerprint mfr:"0084", prod:"0093", model:"0114", deviceJoinName: "Glentronics Connection Module" + fingerprint mfr:"0084", prod:"0093", model:"0114", deviceJoinName: "Glentronics Water Leak Sensor" //Glentronics Connection Module } tiles (scale: 2){ diff --git a/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy b/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy index c3643e3614f..72f1596b0fb 100644 --- a/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy +++ b/devicetypes/smartthings/home-energy-meter.src/home-energy-meter.groovy @@ -21,8 +21,8 @@ metadata { command "reset" - fingerprint deviceId: "0x3103", inClusters: "0x32" - fingerprint inClusters: "0x32" + fingerprint deviceId: "0x3103", inClusters: "0x32", deviceJoinName: "Energy Monitor" + fingerprint inClusters: "0x32", deviceJoinName: "Energy Monitor" } // simulator metadata diff --git a/devicetypes/smartthings/homeseer-multisensor.src/homeseer-multisensor.groovy b/devicetypes/smartthings/homeseer-multisensor.src/homeseer-multisensor.groovy index ce51302ff28..cc988a28a07 100644 --- a/devicetypes/smartthings/homeseer-multisensor.src/homeseer-multisensor.groovy +++ b/devicetypes/smartthings/homeseer-multisensor.src/homeseer-multisensor.groovy @@ -20,7 +20,7 @@ metadata { capability "Sensor" capability "Battery" - fingerprint deviceId: "0x2101", inClusters: "0x60,0x31,0x70,0x84,0x85,0x80,0x72,0x77,0x86" + fingerprint deviceId: "0x2101", inClusters: "0x60,0x31,0x70,0x84,0x85,0x80,0x72,0x77,0x86", deviceJoinName: "HomeSeer Multipurpose Sensor" } simulator { diff --git a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy index 8c8fbff0f09..756465aecdd 100644 --- a/devicetypes/smartthings/ikea-button.src/ikea-button.groovy +++ b/devicetypes/smartthings/ikea-button.src/ikea-button.groovy @@ -27,8 +27,11 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint inClusters: "0000, 0001, 0003, 0009, 0B05, 1000", outClusters: "0003, 0004, 0005, 0006, 0008, 0019, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI remote control", deviceJoinName: "IKEA TRÅDFRI Remote", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_Remote_Control" - fingerprint inClusters: "0000, 0001, 0003, 0009, 0102, 1000, FC7C", outClusters: "0003, 0004, 0006, 0008, 0019, 0102, 1000", manufacturer:"IKEA of Sweden", model: "TRADFRI on/off switch", deviceJoinName: "IKEA TRÅDFRI On/Off switch", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_On/Off_Switch" + fingerprint inClusters: "0000, 0001, 0003, 0009, 0B05, 1000", outClusters: "0003, 0004, 0005, 0006, 0008, 0019, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI remote control", deviceJoinName: "IKEA Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_Remote_Control" //IKEA TRÅDFRI Remote + fingerprint inClusters: "0000, 0001, 0003, 0009, 0102, 1000, FC7C", outClusters: "0003, 0004, 0006, 0008, 0019, 0102, 1000", manufacturer:"IKEA of Sweden", model: "TRADFRI on/off switch", deviceJoinName: "IKEA Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_On/Off_Switch" //IKEA TRÅDFRI On/Off switch + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI open/close remote", deviceJoinName: "IKEA Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_open/close_remote" // raw description 01 0104 0203 01 07 0000 0001 0003 0009 0020 1000 FC7C 07 0003 0004 0006 0008 0019 0102 1000 //IKEA TRÅDFRI Open/Close Remote + fingerprint manufacturer: "KE", model: "TRADFRI open/close remote", deviceJoinName: "IKEA Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-IKEA_TRADFRI_open/close_remote" // raw description 01 0104 0203 01 07 0000 0001 0003 0009 0020 1000 FC7C 07 0003 0004 0006 0008 0019 0102 1000 //IKEA TRÅDFRI Open/Close Remote + fingerprint manufacturer: "SOMFY", model: "Situo 4 Zigbee", deviceJoinName: "SOMFY Remote Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-Somfy_open/close_remote" // raw description 01 0104 0203 00 02 0000 0003 04 0003 0005 0006 0102 } tiles { @@ -48,6 +51,7 @@ metadata { private getCLUSTER_GROUPS() { 0x0004 } private getCLUSTER_SCENES() { 0x0005 } +private getCLUSTER_WINDOW_COVERING() { 0x0102 } private getREMOTE_BUTTONS() { [TOP:1, @@ -62,6 +66,18 @@ private getONOFFSWITCH_BUTTONS() { BOTTOM:1] } +private getOPENCLOSE_BUTTONS() { + [UP:1, + DOWN:2] +} + +private getOPENCLOSESTOP_BUTTONS() { + [UP:1, + STOP:2, + DOWN:3 + ] +} + private channelNumber(String dni) { dni.split(":")[-1] as Integer } @@ -82,6 +98,21 @@ private getIkeaOnOffSwitchNames() { ] } +private getOpenCloseRemoteNames() { + [ + "Up", // Up button + "Down" // Down button + ] +} + +private getOpenCloseStopRemoteNames() { + [ + "Up", // Up button + "Stop", // Stop button + "Down" // Down button + ] +} + private getButtonLabel(buttonNum) { def label = "Button ${buttonNum}" @@ -89,6 +120,10 @@ private getButtonLabel(buttonNum) { label = ikeaRemoteControlNames[buttonNum - 1] } else if (isIkeaOnOffSwitch()) { label = ikeaOnOffSwitchNames[buttonNum - 1] + } else if (isIkeaOpenCloseRemote()) { + label = openCloseRemoteNames[buttonNum - 1] + } else if (isSomfySituo()) { + label = openCloseStopRemoteNames[buttonNum - 1] } return label @@ -105,7 +140,7 @@ private void createChildButtonDevices(numberOfButtons) { for (i in 1..numberOfButtons) { log.debug "Creating child $i" - def supportedButtons = (isIkeaRemoteControl() && i == REMOTE_BUTTONS.MIDDLE) ? ["pushed"] : ["pushed", "held"] + def supportedButtons = ((isIkeaRemoteControl() && i == REMOTE_BUTTONS.MIDDLE) || isIkeaOpenCloseRemote() || isSomfySituo()) ? ["pushed"] : ["pushed", "held"] def child = addChildDevice("Child Button", "${device.deviceNetworkId}:${i}", device.hubId, [completedSetup: true, label: getButtonName(i), isComponent: true, componentName: "button$i", componentLabel: getButtonLabel(i)]) @@ -121,15 +156,18 @@ def installed() { if (isIkeaRemoteControl()) { numberOfButtons = 5 - } else if (isIkeaOnOffSwitch()) { + } else if (isIkeaOnOffSwitch() || isIkeaOpenCloseRemote()) { numberOfButtons = 2 + } else if (isSomfySituo()) { + numberOfButtons = 3 } if (numberOfButtons > 1) { createChildButtonDevices(numberOfButtons) } - sendEvent(name: "supportedButtonValues", value: ["pushed", "held"].encodeAsJSON(), displayed: false) + def supportedButtons = isIkeaOpenCloseRemote() || isSomfySituo() ? ["pushed"] : ["pushed", "held"] + sendEvent(name: "supportedButtonValues", value: supportedButtons.encodeAsJSON(), displayed: false) sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false) numberOfButtons.times { sendEvent(name: "button", value: "pushed", data: [buttonNumber: it+1], displayed: false) @@ -152,11 +190,19 @@ def updated() { def configure() { log.debug "Configuring device ${device.getDataValue("model")}" - def cmds = zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21, DataType.UINT8, 30, 21600, 0x01) + - zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21) + - zigbee.addBinding(zigbee.ONOFF_CLUSTER) + - readDeviceBindingTable() // Need to read the binding table to see what group it's using + def cmds = [] + + if (isSomfySituo()) { + cmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21, ["destEndpoint":0xE8]) + + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21, DataType.UINT8, 30, 21600, 0x01, ["destEndpoint":0xE8]) + + zigbee.addBinding(CLUSTER_WINDOW_COVERING) + } else { + cmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21) + + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, 0x21, DataType.UINT8, 30, 21600, 0x01) + + zigbee.addBinding(zigbee.ONOFF_CLUSTER) + } + cmds += readDeviceBindingTable() // Need to read the binding table to see what group it's using cmds } @@ -170,10 +216,15 @@ def parse(String description) { if ((description?.startsWith("catchall:")) || (description?.startsWith("read attr -"))) { def descMap = zigbee.parseDescriptionAsMap(description) if (descMap.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.attrInt == 0x0021) { - event = getBatteryEvent(zigbee.convertHexToInt(descMap.value)) + def batteryValue = zigbee.convertHexToInt(descMap.value) + if (!isIkea()) { + batteryValue = batteryValue / 2 + } + event = getBatteryEvent(batteryValue) } else if (descMap.clusterInt == CLUSTER_SCENES || - descMap.clusterInt == zigbee.ONOFF_CLUSTER || - descMap.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER) { + descMap.clusterInt == zigbee.ONOFF_CLUSTER || + descMap.clusterInt == zigbee.LEVEL_CONTROL_CLUSTER || + descMap.clusterInt == CLUSTER_WINDOW_COVERING) { event = getButtonEvent(descMap) } } @@ -233,11 +284,11 @@ private Map getButtonEvent(Map descMap) { 0x07: { [state: "", buttonNumber: 0] }], (CLUSTER_SCENES): [0x07: { it == "00" - ? [state: "pushed", buttonNumber: REMOTE_BUTTONS.RIGHT] - : [state: "pushed", buttonNumber: REMOTE_BUTTONS.LEFT] }, + ? [state: "pushed", buttonNumber: REMOTE_BUTTONS.RIGHT] + : [state: "pushed", buttonNumber: REMOTE_BUTTONS.LEFT] }, 0x08: { it == "00" - ? [state: "held", buttonNumber: REMOTE_BUTTONS.RIGHT] - : [state: "held", buttonNumber: REMOTE_BUTTONS.LEFT] }, + ? [state: "held", buttonNumber: REMOTE_BUTTONS.RIGHT] + : [state: "held", buttonNumber: REMOTE_BUTTONS.LEFT] }, 0x09: { [state: "", buttonNumber: 0] }] ] @@ -265,12 +316,32 @@ private Map getButtonEvent(Map descMap) { buttonNumber = ONOFFSWITCH_BUTTONS.TOP } } + } else if (isIkeaOpenCloseRemote()){ + if (descMap.clusterInt == CLUSTER_WINDOW_COVERING) { + buttonState = "pushed" + if (descMap.commandInt == 0x00) { + buttonNumber = OPENCLOSE_BUTTONS.UP + } else if (descMap.commandInt == 0x01) { + buttonNumber = OPENCLOSE_BUTTONS.DOWN + } + } + } else if (isSomfySituo()){ + if (descMap.clusterInt == CLUSTER_WINDOW_COVERING) { + buttonState = "pushed" + if (descMap.commandInt == 0x00) { + buttonNumber = OPENCLOSESTOP_BUTTONS.UP + } else if (descMap.commandInt == 0x01) { + buttonNumber = OPENCLOSESTOP_BUTTONS.DOWN + } else if (descMap.commandInt == 0x02) { + buttonNumber = OPENCLOSESTOP_BUTTONS.STOP + } + } } if (buttonNumber != 0) { // Create old style def descriptionText = "${getButtonName(buttonNumber)} was $buttonState" - result = [name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true] + result = [name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true, displayed: false] // Create and send component event sendButtonEvent(buttonNumber, buttonState) @@ -286,6 +357,18 @@ private boolean isIkeaOnOffSwitch() { device.getDataValue("model") == "TRADFRI on/off switch" } +private boolean isIkeaOpenCloseRemote() { + device.getDataValue("model") == "TRADFRI open/close remote" +} + +private boolean isIkea() { + isIkeaRemoteControl() || isIkeaOnOffSwitch() || isIkeaOpenCloseRemote() +} + +private boolean isSomfySituo() { + device.getDataValue("model") == "Situo 4 Zigbee" +} + private Integer getGroupAddrFromBindingTable(description) { log.info "Parsing binding table - '$description'" def btr = zigbee.parseBindingTableResponse(description) @@ -307,4 +390,4 @@ private List addHubToGroup(Integer groupAddr) { private List readDeviceBindingTable() { ["zdo mgmt-bind 0x${device.deviceNetworkId} 0", "delay 200"] -} +} \ No newline at end of file diff --git a/devicetypes/smartthings/ikea-motion-sensor.src/ikea-motion-sensor.groovy b/devicetypes/smartthings/ikea-motion-sensor.src/ikea-motion-sensor.groovy index 2c6b68b47a1..e8d1a2817d2 100644 --- a/devicetypes/smartthings/ikea-motion-sensor.src/ikea-motion-sensor.groovy +++ b/devicetypes/smartthings/ikea-motion-sensor.src/ikea-motion-sensor.groovy @@ -23,7 +23,7 @@ metadata { capability "Health Check" capability "Refresh" - fingerprint inClusters: "0000, 0001, 0003, 0009, 0B05, 1000", outClusters: "0003, 0004, 0006, 0019, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI motion sensor", deviceJoinName: "IKEA TRÅDFRI Motion Sensor" + fingerprint inClusters: "0000, 0001, 0003, 0009, 0B05, 1000", outClusters: "0003, 0004, 0006, 0019, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI motion sensor", deviceJoinName: "IKEA Motion Sensor" //IKEA TRÅDFRI Motion Sensor } tiles(scale: 2) { diff --git a/devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy b/devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy new file mode 100644 index 00000000000..c883a81c017 --- /dev/null +++ b/devicetypes/smartthings/inovelli-dimmer.src/inovelli-dimmer.groovy @@ -0,0 +1,585 @@ +/* Copyright 2020 SmartThings +* +* 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. +* +* Inovelli Dimmer +* +* Copyright 2020 SmartThings +* +*/ +metadata { + definition(name: "Inovelli Dimmer", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch", mcdSync: true) { + capability "Actuator" + capability "Configuration" + capability "Energy Meter" + capability "Health Check" + capability "Refresh" + capability "Sensor" + capability "Switch" + capability "Switch Level" + capability "Power Meter" + + fingerprint mfr: "031E", prod: "0001", model: "0001", deviceJoinName: "Inovelli Dimmer Switch", mnmn: "SmartThings", vid: "SmartThings-smartthings-Inovelli_Dimmer" //Inovelli Dimmer LZW31-SN + fingerprint mfr: "031E", prod: "0003", model: "0001", deviceJoinName: "Inovelli Dimmer Switch", mnmn: "SmartThings", vid: "SmartThings-smartthings-Inovelli_Dimmer_LZW31" //Inovelli Dimmer LZW31 + } + + tiles(scale: 2) { + multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) { + tileAttribute("device.switch", key: "PRIMARY_CONTROL") { + attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff" + attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn" + } + tileAttribute("device.level", key: "SLIDER_CONTROL") { + attributeState "level", action: "switch level.setLevel" + } + } + valueTile("power", "device.power", width: 2, height: 2) { + state "default", label: '${currentValue} W' + } + valueTile("energy", "device.energy", width: 2, height: 2) { + state "default", label: '${currentValue} kWh' + } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh" + } + } + + main(["switch", "power", "energy"]) + details(["switch", "power", "energy", "refresh"]) + + preferences { + // Preferences template begin + parameterMap.each { + input(title: it.name, description: it.description, type: "paragraph", element: "paragraph") + + switch (it.type) { + case "boolRange": + input( + name: it.key + "Boolean", type: "bool", title: "Enable", description: "If you disable this option, it will overwrite setting below.", + defaultValue: it.defaultValue != it.disableValue, required: false + ) + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + case "boolean": + input( + type: "paragraph", element: "paragraph", + description: "Option enabled: ${it.activeDescription}\n" + "Option disabled: ${it.inactiveDescription}" + ) + input( + name: it.key, type: "bool", title: "Enable", + defaultValue: it.defaultValue == it.activeOption, required: false + ) + break + case "enum": + input( + name: it.key, title: "Select", type: "enum", + options: it.values, defaultValue: it.defaultValue, required: false + ) + break + case "range": + input( + name: it.key, type: "number", title: "Set value (range ${it.range})", + defaultValue: it.defaultValue, range: it.range, required: false + ) + break + } + } + // Preferences template end + } +} + +private getUP_BUTTON(){ 1 } +private getDOWN_BUTTON(){ 2 } +private getCONFIGURATION_BUTTON(){ 3 } + +def installed() { + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + + // Preferences template begin + state.currentPreferencesState = [:] + parameterMap.each { + state.currentPreferencesState."$it.key" = [:] + state.currentPreferencesState."$it.key".value = getPreferenceValue(it) + if (it.type == "boolRange" && getPreferenceValue(it) == it.disableValue) { + state.currentPreferencesState."$it.key".status = "disablePending" + } else { + state.currentPreferencesState."$it.key".status = "synced" + } + } +// Preferences template end + if(isInovelliDimmerLZW31SN()) { + createChildButtonDevices() + def value = ['pushed', 'pushed_2x', 'pushed_3x', 'pushed_4x', 'pushed_5x'].encodeAsJson() + sendEvent(name: "supportedButtonValues", value: value) + sendEvent(name: "numberOfButtons", value: 3, displayed: true) + } + createChildDevice("smartthings", "Child Color Control", "${device.deviceNetworkId}:4", "LED Bar", "LEDColorConfiguration") +} + +def configure() { + sendHubCommand(getReadConfigurationFromTheDeviceCommands()) +} + +def updated() { + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Preferences template begin + parameterMap.each { + if (isPreferenceChanged(it)) { + log.debug "Preference ${it.key} has been updated from value: ${state.currentPreferencesState."$it.key".value} to ${settings."$it.key"}" + state.currentPreferencesState."$it.key".status = "syncPending" + if (it.type == "boolRange") { + def preferenceName = it.key + "Boolean" + + if (isNotNull(settings."$preferenceName")) { + if (!settings."$preferenceName") { + state.currentPreferencesState."$it.key".status = "disablePending" + } else if (state.currentPreferencesState."$it.key".status == "disabled") { + state.currentPreferencesState."$it.key".status = "syncPending" + } + } else { + state.currentPreferencesState."$it.key".status = "syncPending" + } + } + } else if (state.currentPreferencesState."$it.key".value == null) { + log.warn "Preference ${it.key} no. ${it.parameterNumber} has no value. Please check preference declaration for errors." + } + } + syncConfiguration() + // Preferences template end + + response(refresh()) +} + +private getReadConfigurationFromTheDeviceCommands() { + def commands = [] + parameterMap.each { + state.currentPreferencesState."$it.key".status = "reverseSyncPending" + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + commands +} + +private syncConfiguration() { + def commands = [] + log.debug "syncConfiguration ${settings}" + parameterMap.each { + if (state.currentPreferencesState."$it.key".status == "syncPending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: getCommandValue(it), parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } else if (state.currentPreferencesState."$it.key".status == "disablePending") { + commands += encap(zwave.configurationV2.configurationSet(scaledConfigurationValue: it.disableValue, parameterNumber: it.parameterNumber, size: it.size)) + commands += encap(zwave.configurationV2.configurationGet(parameterNumber: it.parameterNumber)) + } + } + sendHubCommand(commands) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + if (cmd.parameterNumber == 13) { + handleLEDPreferenceEvent(cmd) + } else { + // Preferences template begin + log.debug "Configuration report: ${cmd}" + def preference = parameterMap.find({ it.parameterNumber == cmd.parameterNumber }) + def key = preference.key + def preferenceValue = getPreferenceValue(preference, cmd.scaledConfigurationValue) + log.debug "settings.key ${settings."$key"} preferenceValue ${preferenceValue}" + + if (state.currentPreferencesState."$key".status == "reverseSyncPending") { + log.debug "reverseSyncPending" + state.currentPreferencesState."$key".value = preferenceValue + state.currentPreferencesState."$key".status = "synced" + } else { + if (preferenceValue instanceof String && settings."$key" == preferenceValue.toBoolean()) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + } else if (preferenceValue instanceof Integer && settings."$key" == preferenceValue) { + state.currentPreferencesState."$key".value = settings."$key" + state.currentPreferencesState."$key".status = "synced" + } else if (preference.type == "boolRange") { + log.debug "${state.currentPreferencesState."$key".status}" + if (state.currentPreferencesState."$key".status == "disablePending" && preferenceValue == preference.disableValue) { + state.currentPreferencesState."$key".status = "disabled" + } else { + runIn(5, "syncConfiguration", [overwrite: true]) + } + } else { + state.currentPreferencesState."$key"?.status = "syncPending" + runIn(5, "syncConfiguration", [overwrite: true]) + } + } + // Preferences template end + } +} + +private getPreferenceValue(preference, value = "default") { + def integerValue = value == "default" ? preference.defaultValue : value.intValue() + switch (preference.type) { + case "enum": + return String.valueOf(integerValue) + case "boolean": + return String.valueOf(preference.optionActive == integerValue) + default: + return integerValue + } +} + +private getCommandValue(preference) { + def parameterKey = preference.key + log.debug "settings parameter key ${settings."$parameterKey"} ${preference} " + switch (preference.type) { + case "boolean": + return settings."$parameterKey" ? preference.optionActive : preference.optionInactive + case "boolRange": + def parameterKeyBoolean = parameterKey + "Boolean" + return !isNotNull(settings."$parameterKeyBoolean") || settings."$parameterKeyBoolean" ? settings."$parameterKey" : preference.disableValue + case "range": + return settings."$parameterKey" + default: + return Integer.parseInt(settings."$parameterKey") + } +} + +private isNotNull(value) { + return value != null +} + +private isPreferenceChanged(preference) { + if (isNotNull(settings."$preference.key")) { + if (preference.type == "boolRange") { + def boolName = preference.key + "Boolean" + if (state.currentPreferencesState."$preference.key".status == "disabled") { + return settings."$boolName" + } else { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" || !settings."$boolName" + } + } else { + return state.currentPreferencesState."$preference.key".value != settings."$preference.key" + } + } else { + return false + } +} + +def parse(String description) { + def result = null + if (description != "updated") { + def cmd = zwave.parse(description) + if (cmd) { + result = zwaveEvent(cmd) + log.debug("'$description' parsed to $result") + } else { + log.debug("Couldn't zwave.parse '$description'") + } + } + log.debug "parsed '${description}' to ${result.inspect()}" + result +} + +def handleLEDPreferenceEvent(cmd) { + def hueState = [name: "hue", value: "${Math.round(zwaveValueToHuePercent(cmd.scaledConfigurationValue))}"] + def childDni = "${device.deviceNetworkId}:4" + def childDevice = childDevices.find { it.deviceNetworkId == childDni } + childDevice?.sendEvent(hueState) + childDevice?.sendEvent(name: "saturation", value: "100") +} + +def createChildDevice(childDthNamespace, childDthName, childDni, childComponentLabel, childComponentName) { + try { + log.debug "Creating a child device: ${childDthNamespace}, ${childDthName}, ${childDni}, ${childComponentLabel}, ${childComponentName}" + addChildDevice(childDthNamespace, childDthName, childDni, device.hub.id, + [ + completedSetup: true, + label : childComponentLabel, + isComponent : true, + componentName : childComponentName, + componentLabel: childComponentLabel + ]) + } catch (Exception e) { + log.debug "Exception: ${e}" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + dimmerEvents(cmd) +} + +def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelReport cmd) { + dimmerEvents(cmd) +} + +def dimmerEvents(physicalgraph.zwave.Command cmd) { + def switchEvent = createEvent([name: "switch", value: cmd.value ? "on" : "off", descriptionText: "$device.displayName was turned ${cmd.value ? "on" : "off"}"]) + def dimmerEvent = createEvent([name: "level", value: cmd.value == 99 ? 100 : cmd.value, unit: "%"]) + def result = [switchEvent, dimmerEvent] + if (switchEvent.isStateChange) { + result << response(["delay 1000", zwave.meterV3.meterGet(scale: 2).format()]) + } + return result +} + +def on() { + encapSequence([ + zwave.basicV1.basicSet(value: 0xFF), + zwave.basicV1.basicGet() + ], 1000) +} + +def off() { + encapSequence([ + zwave.basicV1.basicSet(value: 0x00), + zwave.basicV1.basicGet() + ], 1000) +} + +def setLevel(level) { + if (level > 99) level = 99 + encapSequence([ + zwave.basicV1.basicSet(value: level), + zwave.switchMultilevelV1.switchMultilevelGet() + ], 1000) +} + +def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) { + def map = [:] + if (cmd.meterType == 1 && cmd.scale == 0) { + map = [name: "energy", value: cmd.scaledMeterValue.toDouble().round(1), unit: "kWh"] + } else if (cmd.meterType == 1 && cmd.scale == 2) { + map = [name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W"] + } + createEvent(map) +} + +private getButtonLabel() { + [ + "Up button", + "Down button", + "Configuration button" + ] +} + +private void createChildButtonDevices() { + for (buttonNumber in 1..3) { + def child = addChildDevice("smartthings", "Child Button", "${device.deviceNetworkId}:${buttonNumber}", device.hub.id, + [ + completedSetup: true, + label : buttonLabel[buttonNumber - 1], + isComponent : true, + componentName : "button$buttonNumber", + componentLabel: buttonLabel[buttonNumber - 1] + ]) + + def value = buttonNumber == 3 ? ['pushed'] : ['pushed', 'pushed_2x', 'pushed_3x', 'pushed_4x', 'pushed_5x'] + child.sendEvent(name: "supportedButtonValues", value: value.encodeAsJSON(), displayed: false) + child.sendEvent(name: "numberOfButtons", value: 1, displayed: false) + child.sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], displayed: false) + } +} + +def sendButtonEvent(gesture, buttonNumber) { + def event = createEvent([name: "button", value: gesture, data: [buttonNumber: buttonNumber], isStateChange: true]) + String childDni = "${device.deviceNetworkId}:$buttonNumber" + def child = childDevices.find { it.deviceNetworkId == childDni } + child?.sendEvent(event) + return createEvent([name: "button", value: gesture, data: [buttonNumber: buttonNumber], isStateChange: true, displayed: false]) +} + +def labelForGesture( attribute) { + def gesture = "pushed" + if (attribute == 0) { + gesture; + } else { + def number = attribute - 1; + "${gesture}_${number}x"; + } +} + +def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { + log.info("CentralSceneNotification, keyAttributes=${cmd.keyAttributes}, sceneNumber=${cmd.sceneNumber}") + def singleClick = 0; + def multipleClicks = [3, 4, 5, 6] + def supportedAttributes = [singleClick] + multipleClicks + int attribute = cmd.keyAttributes + int scene = cmd.sceneNumber + if (scene == 1 && attribute in supportedAttributes) { + sendButtonEvent(labelForGesture(attribute), DOWN_BUTTON); + } else if (scene == 2 && attribute in supportedAttributes) { + sendButtonEvent(labelForGesture(attribute), UP_BUTTON); + } else if (scene == 3 && attribute == singleClick) { + sendButtonEvent("pushed", CONFIGURATION_BUTTON) + } else { + log.warn("Unhandled scene notification, keyAttributes=${attribute}, sceneNumber=${scene}") + } +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + // Handles all Z-Wave commands we aren't interested in + log.debug "${cmd}" + [:] +} + +def childSetColor(value) { + sendHubCommand setColorCmd(value) +} + +def setColorCmd(value) { + if (value.hue == null || value.saturation == null) return + def ledColor = Math.round(huePercentToZwaveValue(value.hue)) + encapSequence([ + zwave.configurationV2.configurationSet(scaledConfigurationValue: ledColor, parameterNumber: 13, size: 2), + zwave.configurationV2.configurationGet(parameterNumber: 13) + ], 1000) +} + +private huePercentToZwaveValue(value) { + return value <= 2 ? 0 : (value >= 98 ? 255 : value / 100 * 255) +} + +private zwaveValueToHuePercent(value) { + return value <= 2 ? 0 : (value >= 254 ? 100 : value / 255 * 100) +} + +def refresh() { + encapSequence([ + zwave.basicV1.basicGet(), + zwave.meterV3.meterGet(scale: 0) + ], 1000) +} + +/* +* Security encapsulation support: +*/ + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) + if (encapsulatedCommand) { + log.debug "Parsed SecurityMessageEncapsulation into: ${encapsulatedCommand}" + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract Secure command from $cmd" + } +} + +def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { + def version = commandClassVersions[cmd.commandClass as Integer] + def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass) + def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data) + if (encapsulatedCommand) { + log.debug "Parsed Crc16Encap into: ${encapsulatedCommand}" + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract CRC16 command from $cmd" + } +} + +private secEncap(physicalgraph.zwave.Command cmd) { + log.debug "encapsulating command using Secure Encapsulation, command: $cmd" + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() +} + +private crcEncap(physicalgraph.zwave.Command cmd) { + log.debug "encapsulating command using CRC16 Encapsulation, command: $cmd" + zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format() +} + +private encap(cmd, endpoint = null) { + if (cmd) { + if (endpoint) { + cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) + } + + if (zwaveInfo.zw.endsWith("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } + } +} + +private encapSequence(cmds, Integer delay = 250) { + delayBetween(cmds.collect { encap(it) }, delay) +} + +private isInovelliDimmerLZW31SN(){ + zwaveInfo.mfr.equals("031E") && zwaveInfo.prod.equals("0001") && zwaveInfo.model.equals("0001") +} + +private getParameterMap() { + [ + [ + name : "Dimming Speed", key: "dimmingSpeed", type: "range", + parameterNumber: 1, size: 1, defaultValue: 3, + range : "1..100", + description : "How fast or slow the light turns on when you hold the switch in seconds (ie: dimming from 10-20%, 80-60%, etc). Value 0 - Instant On. This parameter can be set without a HUB from the Configuration Button. Finally, if you are using a,dumb switch in a 3-Way setting, this parameter will not work if you manually press the dumb switch (it will only work if you press the smart switch)." + ], + [ + name : "Power On State", key: "powerOnState", type: "range", + parameterNumber: 11, size: 1, defaultValue: 0, + range : "0..101", + description : "When power is restored, the switch reverts to either On, Off, or Last Level. Example of how the values work: 0 = Off, 1-100 = Specific % On, 101 = Returns to Level before Power Outage. This parameter can be set without a HUB from the Configuration Button." + ], + [ + name : "LED Indicator Intensity", key: "ledIndicatorIntensity", type: "range", + parameterNumber: 14, size: 1, defaultValue: 5, + range : "0..10", + description : "This will set the intensity of the LED bar (ie: how bright it is). Example of how the values work: 0 = Off, 1 = Low, 5 = Medium, 10 = High. This parameter can be set without a HUB from the Configuration Button." + ], + [ + name : "LED Indicator Intensity (When Off)", key: "ledIndicatorIntensity(WhenOff)", type: "range", + parameterNumber: 15, size: 1, defaultValue: 1, + range : "0..10", + description : "This is the intensity of the LED bar when the switch is off. Example of how the values work: 0 = Off, 1 = Low, 5 = Medium, 10 = High. This parameter can be set without a HUB from the Configuration Button." + ], + [ + name : "LED Indicator Timeout", key: "ledIndicatorTimeout", type: "range", + parameterNumber: 17, size: 1, defaultValue: 3, + range : "0..10", + description : "Changes the amount of time the RGB Bar shows the Dim level if the LED Bar has been disabled. Example of how the values work: 0 = Always off, 1 = 1 second after level is adjusted." + ], + [ + name : "Dimming Speed (Z-Wave)", key: "dimmingSpeed(Z-Wave)", type: "range", + parameterNumber: 2, size: 1, defaultValue: 101, + range : "0..101", + description : "How fast or slow the light turns dim when you adjust the switch remotely (ie: dimming from 10-20%, 80-60%, etc). Entering the value of 101 = Keeps the switch in sync with Parameter 1." + ], + [ + name : "Ramp Rate", key: "rampRate", type: "range", + parameterNumber: 3, size: 1, defaultValue: 101, + range : "0..101", + description : "How fast or slow the light turns on when you press the switch 1x to bring from On to Off or Off to On. Entering the value of 101 = Keeps the switch in sync with Parameter 1." + ], + [ + name : "Ramp Rate (Z-Wave)", key: "rampRate(Z-Wave)", type: "range", + parameterNumber: 4, size: 1, defaultValue: 101, + range : "0..101", + description : "How fast or slow the light turns on when you bring your switch from On to Off or Off to On remotely. Entering the value of 101 = Keeps the switch in sync with Parameter 1." + ], + [ + name : "Invert Switch", key: "invertSwitch", type: "boolean", + parameterNumber: 7, size: 1, defaultValue: 0, + optionInactive : 0, inactiveDescription: "Disabled", + optionActive : 1, activeDescription: "Enabled", + description : "Inverts the switch" + ], + [ + name : "Auto Off Timer", key: "autoOffTimer", type: "boolRange", + parameterNumber: 8, size: 2, defaultValue: 0, + range : "1..32767", disableValue: 0, + description : "Automatically turns the switch off after x amount of seconds (value 0 = Disabled)" + ] + ] +} diff --git a/devicetypes/smartthings/leaksmart-water-sensor.src/leaksmart-water-sensor.groovy b/devicetypes/smartthings/leaksmart-water-sensor.src/leaksmart-water-sensor.groovy index 8b50465114e..4d43052aa41 100644 --- a/devicetypes/smartthings/leaksmart-water-sensor.src/leaksmart-water-sensor.groovy +++ b/devicetypes/smartthings/leaksmart-water-sensor.src/leaksmart-water-sensor.groovy @@ -26,7 +26,7 @@ metadata { capability "Water Sensor" capability "Temperature Measurement" - fingerprint inClusters: "0000,0001,0003,0402,0B02,FC02", outClusters: "0003,0019", manufacturer: "WAXMAN", model: "leakSMART Water Sensor V2", deviceJoinName: "leakSMART Water Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0B02,FC02", outClusters: "0003,0019", manufacturer: "WAXMAN", model: "leakSMART Water Sensor V2", deviceJoinName: "leakSMART Water Leak Sensor" //leakSMART Water Sensor } tiles(scale: 2) { @@ -74,7 +74,7 @@ def parse(String description) { map = parseAttrMessage(description) } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? "${device.displayName} was ${map.value}°C" : "${device.displayName} was ${map.value}°F" map.translatable = true diff --git a/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy b/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy deleted file mode 100644 index 065c8a125b6..00000000000 --- a/devicetypes/smartthings/lifx-color-bulb.src/lifx-color-bulb.groovy +++ /dev/null @@ -1,253 +0,0 @@ -/** - * LIFX Color Bulb - * - * Copyright 2015 LIFX - * - */ -metadata { - definition (name: "LIFX Color Bulb", namespace: "smartthings", author: "LIFX", ocfDeviceType: "oic.d.light", cloudDeviceHandler: "smartthings.cdh.handlers.LifxLightHandler") { - capability "Actuator" - capability "Color Control" - capability "Color Temperature" - capability "Switch" - capability "Switch Level" // brightness - capability "Refresh" - capability "Sensor" - capability "Health Check" - capability "Light" - } - - simulator { - - } - - tiles(scale: 2) { - multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ - tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { - attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff" - attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn" - attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff" - attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn" - } - - tileAttribute ("device.level", key: "SLIDER_CONTROL") { - attributeState "level", action:"switch level.setLevel" - } - - tileAttribute ("device.color", key: "COLOR_CONTROL") { - attributeState "color", action:"setColor" - } - - tileAttribute ("device.model", key: "SECONDARY_CONTROL") { - attributeState "model", label: '${currentValue}' - } - } - - standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { - state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" - } - - valueTile("null", "device.switch", inactiveLabel: false, decoration: "flat") { - state "default", label:'' - } - - controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 2, width: 4, inactiveLabel: false, range:"(2700..9000)") { - state "colorTemp", action:"color temperature.setColorTemperature" - } - - valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", height: 2, width: 2) { - state "colorTemp", label: '${currentValue}K' - } - - main "switch" - details(["switch", "colorTempSliderControl", "colorTemp", "refresh"]) - } -} - -def initialize() { - sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}", displayed: false) -} - -void installed() { - log.debug "installed()" - initialize() -} - -def updated() { - log.debug "updated()" - initialize() -} - -// handle commands -def setHue(percentage) { - log.debug "setHue ${percentage}" - parent.logErrors(logObject: log) { - def resp = parent.apiPUT("/lights/${selector()}/state", [color: "hue:${percentage * 3.6}", power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "hue", value: percentage) - sendEvent(name: "switch", value: "on") - } else { - log.error("Bad setHue result: [${resp.status}] ${resp.data}") - } - } - return [] -} - -def setSaturation(percentage) { - log.debug "setSaturation ${percentage}" - parent.logErrors(logObject: log) { - def resp = parent.apiPUT("/lights/${selector()}/state", [color: "saturation:${percentage / 100}", power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "saturation", value: percentage) - sendEvent(name: "switch", value: "on") - } else { - log.error("Bad setSaturation result: [${resp.status}] ${resp.data}") - } - } - return [] -} - -def setColor(Map color) { - log.debug "setColor ${color}" - def attrs = [] - def events = [] - color.each { key, value -> - switch (key) { - case "hue": - attrs << "hue:${value * 3.6}" - events << createEvent(name: "hue", value: value) - break - case "saturation": - attrs << "saturation:${value / 100}" - events << createEvent(name: "saturation", value: value) - break - case "colorTemperature": - attrs << "kelvin:${value}" - events << createEvent(name: "colorTemperature", value: value) - break - } - } - parent.logErrors(logObject:log) { - def resp = parent.apiPUT("/lights/${selector()}/state", [color: attrs.join(" "), power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - if (color.hex) - sendEvent(name: "color", value: color.hex) - sendEvent(name: "switch", value: "on") - events.each { sendEvent(it) } - } else { - log.error("Bad setColor result: [${resp.status}] ${resp.data}") - } - } - return [] -} - -def setLevel(percentage, rate = null) { - log.debug "setLevel ${percentage}" - if (percentage < 1 && percentage > 0) { - percentage = 1 // clamp to 1% - } else { - try { - percentage = Math.round(percentage) - } catch (Exception ex) { - log.error "Caught exception while converting value '$percentage' to integer: $ex" - percentage = 0 - } - } - log.debug "setlevel: using percentage value of $percentage" - - if (percentage == 0) { - return off() // if the brightness is set to 0, just turn it off - } - parent.logErrors(logObject:log) { - def resp = parent.apiPUT("/lights/${selector()}/state", ["brightness": percentage / 100, "power": "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "level", value: percentage) - sendEvent(name: "switch", value: "on") - } else { - log.error("Bad setLevel result: [${resp.status}] ${resp.data}") - sendEvent(name: "level", value: device.currentValue("level"), isStateChange: true, displayed: false) - sendEvent(name: "switch.setLevel", value: device.currentValue("level"), isStateChange: true, displayed: false) - } - } - return [] -} - -def setColorTemperature(kelvin) { - log.debug "Executing 'setColorTemperature' to ${kelvin}" - parent.logErrors() { - def resp = parent.apiPUT("/lights/${selector()}/state", [color: "kelvin:${kelvin}", power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "colorTemperature", value: kelvin) - sendEvent(name: "color", value: "#ffffff") - sendEvent(name: "saturation", value: 0) - } else { - log.error("Bad setColorTemperature result: [${resp.status}] ${resp.data}") - } - } - return [] -} - -def on() { - log.debug "Device setOn" - parent.logErrors() { - def resp = parent.apiPUT("/lights/${selector()}/state", [power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "switch", value: "on") - } - } - return [] -} - -def off() { - log.debug "Device setOff" - parent.logErrors() { - def resp = parent.apiPUT("/lights/${selector()}/state", [power: "off"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "switch", value: "off") - } - } - return [] -} - -def refresh() { - log.debug "Executing 'refresh'" - - def resp = parent.apiGET("/lights/${selector()}") - if (resp.status == 404) { - state.online = false - sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false) - log.warn "$device is Offline" - return [] - } else if (resp.status != 200) { - log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}") - return [] - } - def data = resp.data[0] - log.debug("Data: ${data}") - - sendEvent(name: "label", value: data.label) - sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100)) - sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100)) - sendEvent(name: "switch", value: data.power) - sendEvent(name: "color", value: colorUtil.hslToHex((data.color.hue / 3.6) as int, (data.color.saturation * 100) as int)) - sendEvent(name: "hue", value: data.color.hue / 3.6) - sendEvent(name: "saturation", value: data.color.saturation * 100) - sendEvent(name: "colorTemperature", value: data.color.kelvin) - sendEvent(name: "model", value: data.product.name) - - if (data.connected) { - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) - log.debug "$device is Online" - } else { - sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - log.warn "$device is Offline" -} -} - -def selector() { - if (device.deviceNetworkId.contains(":")) { - return device.deviceNetworkId - } else { - return "id:${device.deviceNetworkId}" - } -} diff --git a/devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy b/devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy deleted file mode 100644 index 7634d8ddb49..00000000000 --- a/devicetypes/smartthings/lifx-white-bulb.src/lifx-white-bulb.groovy +++ /dev/null @@ -1,178 +0,0 @@ -/** - * LIFX White Bulb - * - * Copyright 2015 LIFX - * - */ -metadata { - definition (name: "LIFX White Bulb", namespace: "smartthings", author: "LIFX", ocfDeviceType: "oic.d.light", cloudDeviceHandler: "smartthings.cdh.handlers.LifxLightHandler") { - capability "Actuator" - capability "Color Temperature" - capability "Switch" - capability "Switch Level" // brightness - capability "Refresh" - capability "Sensor" - capability "Health Check" - capability "Light" - } - - simulator { - - } - - tiles(scale: 2) { - multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ - tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { - attributeState "on", label:'${name}', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff" - attributeState "off", label:'${name}', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn" - attributeState "turningOn", label:'Turning on', action:"switch.off", icon:"http://hosted.lifx.co/smartthings/v1/196xOn.png", backgroundColor:"#00A0DC", nextState:"turningOff" - attributeState "turningOff", label:'Turning off', action:"switch.on", icon:"http://hosted.lifx.co/smartthings/v1/196xOff.png", backgroundColor:"#ffffff", nextState:"turningOn" - } - - tileAttribute ("device.level", key: "SLIDER_CONTROL") { - attributeState "level", action:"switch level.setLevel" - } - } - - standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { - state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" - } - - valueTile("null", "device.switch", inactiveLabel: false, decoration: "flat") { - state "default", label:'' - } - - controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 2, width: 4, inactiveLabel: false, range:"(2700..9000)") { - state "colorTemp", action:"color temperature.setColorTemperature" - } - - valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", height: 2, width: 2) { - state "colorTemp", label: '${currentValue}K' - } - - main "switch" - details(["switch", "colorTempSliderControl", "colorTemp", "refresh"]) - } -} - -def initialize() { - sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"cloud\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${device?.hub?.hardwareID}\"}", displayed: false) -} - -void installed() { - log.debug "installed()" - initialize() -} - -def updated() { - log.debug "updated()" - initialize() -} - -// handle commands -def setLevel(percentage, rate = null) { - log.debug "setLevel ${percentage}" - if (percentage < 1 && percentage > 0) { - percentage = 1 // clamp to 1% - } else { - try { - percentage = Math.round(percentage) - } catch (Exception ex) { - log.error "Caught exception while converting value '$percentage' to integer: $ex" - percentage = 0 - } - } - log.debug "setlevel: using percentage value of $percentage" - if (percentage == 0) { - return off() // if the brightness is set to 0, just turn it off - } - parent.logErrors(logObject:log) { - def resp = parent.apiPUT("/lights/${selector()}/state", [brightness: percentage / 100, power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "level", value: percentage) - sendEvent(name: "switch", value: "on") - } else { - log.error("Bad setLevel result: [${resp.status}] ${resp.data}") - sendEvent(name: "level", value: device.currentValue("level"), isStateChange: true, displayed: false) - sendEvent(name: "switch.setLevel", value: device.currentValue("level"), isStateChange: true, displayed: false) - } - } - return [] -} - -def setColorTemperature(kelvin) { - log.debug "Executing 'setColorTemperature' to ${kelvin}" - parent.logErrors() { - def resp = parent.apiPUT("/lights/${selector()}/state", [color: "kelvin:${kelvin}", power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "colorTemperature", value: kelvin) - sendEvent(name: "color", value: "#ffffff") - sendEvent(name: "saturation", value: 0) - sendEvent(name: "switch", value: "on") - } else { - log.error("Bad setColorTemperature result: [${resp.status}] ${resp.data}") - } - } - return [] -} - -def on() { - log.debug "Device setOn" - parent.logErrors() { - def resp = parent.apiPUT("/lights/${selector()}/state", [power: "on"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "switch", value: "on") - } - } - return [] -} - -def off() { - log.debug "Device setOff" - parent.logErrors() { - def resp = parent.apiPUT("/lights/${selector()}/state", [power: "off"]) - if (resp.status < 300 && resp.data.results.status[0] == "ok") { - sendEvent(name: "switch", value: "off") - } - } - return [] -} - -def refresh() { - log.debug "Executing 'refresh'" - - def resp = parent.apiGET("/lights/${selector()}") - if (resp.status == 404) { - state.online = false - sendEvent(name: "DeviceWatch-DeviceStatusUpdate", value: "offline", displayed: false) - log.warn "$device is Offline" - return [] - } else if (resp.status != 200) { - log.error("Unexpected result in refresh(): [${resp.status}] ${resp.data}") - return [] - } - def data = resp.data[0] - - sendEvent(name: "label", value: data.label) - sendEvent(name: "level", value: Math.round((data.brightness ?: 1) * 100)) - sendEvent(name: "switch.setLevel", value: Math.round((data.brightness ?: 1) * 100)) - sendEvent(name: "switch", value: data.power) - sendEvent(name: "colorTemperature", value: data.color.kelvin) - sendEvent(name: "model", value: data.product.name) - - if (data.connected) { - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) - log.debug "$device is Online" - } else { - sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - log.warn "$device is Offline" - } -} - -def selector() { - if (device.deviceNetworkId.contains(":")) { - return device.deviceNetworkId - } else { - return "id:${device.deviceNetworkId}" - } -} diff --git a/devicetypes/smartthings/light-sensor.src/light-sensor.groovy b/devicetypes/smartthings/light-sensor.src/light-sensor.groovy index e40731afeed..2b8717c673a 100644 --- a/devicetypes/smartthings/light-sensor.src/light-sensor.groovy +++ b/devicetypes/smartthings/light-sensor.src/light-sensor.groovy @@ -16,7 +16,7 @@ metadata { capability "Illuminance Measurement" capability "Sensor" - fingerprint profileId: "0104", deviceId: "0106", inClusters: "0000,0001,0003,0009,0400" + fingerprint profileId: "0104", deviceId: "0106", inClusters: "0000,0001,0003,0009,0400", deviceJoinName: "Illuminance Sensor" } // simulator metadata diff --git a/devicetypes/smartthings/mimolite-garage-door-controller.src/mimolite-garage-door-controller.groovy b/devicetypes/smartthings/mimolite-garage-door-controller.src/mimolite-garage-door-controller.groovy index c3e91a86b92..ba192827523 100644 --- a/devicetypes/smartthings/mimolite-garage-door-controller.src/mimolite-garage-door-controller.groovy +++ b/devicetypes/smartthings/mimolite-garage-door-controller.src/mimolite-garage-door-controller.groovy @@ -43,7 +43,7 @@ metadata { command "on" command "off" - fingerprint deviceId: "0x1000", inClusters: "0x72,0x86,0x71,0x30,0x31,0x35,0x70,0x85,0x25,0x03" + fingerprint deviceId: "0x1000", inClusters: "0x72,0x86,0x71,0x30,0x31,0x35,0x70,0x85,0x25,0x03", deviceJoinName: "MimoLite Garage Door" } simulator { diff --git a/devicetypes/smartthings/motion-detector.src/motion-detector.groovy b/devicetypes/smartthings/motion-detector.src/motion-detector.groovy index 4cbd258b555..08dfffa86a6 100644 --- a/devicetypes/smartthings/motion-detector.src/motion-detector.groovy +++ b/devicetypes/smartthings/motion-detector.src/motion-detector.groovy @@ -18,8 +18,8 @@ metadata { capability "Motion Sensor" capability "Sensor" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0009,0500" - fingerprint manufacturer: "Aurora", model: "MotionSensor51AU", deviceJoinName: "Aurora Smart PIR Sensor" //raw description 22 0104 0107 00 03 0000 0003 0406 00 + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0009,0500", deviceJoinName: "Motion Sensor" + fingerprint manufacturer: "Aurora", model: "MotionSensor51AU", deviceJoinName: "Aurora Motion Sensor" //raw description 22 0104 0107 00 03 0000 0003 0406 00 //Aurora Smart PIR Sensor } // simulator metadata diff --git a/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy b/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy index a0bbd21f86d..98c22647eb3 100644 --- a/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy +++ b/devicetypes/smartthings/nyce-motion-sensor.src/nyce-motion-sensor.groovy @@ -25,9 +25,9 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3041" - fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3043", deviceJoinName: "NYCE Ceiling Motion Sensor" - fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3045", deviceJoinName: "NYCE Curtain Motion Sensor" + fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3041", deviceJoinName: "NYCE Motion Sensor" + fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3043", deviceJoinName: "NYCE Motion Sensor" //NYCE Ceiling Motion Sensor + fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3045", deviceJoinName: "NYCE Motion Sensor" //NYCE Curtain Motion Sensor } tiles(scale: 2) { diff --git a/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy b/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy index 5b5a9ca5f3d..93388f19289 100644 --- a/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy +++ b/devicetypes/smartthings/nyce-open-closed-sensor.src/nyce-open-closed-sensor.groovy @@ -26,12 +26,12 @@ metadata { capability "Health Check" capability "Sensor" - fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3010", deviceJoinName: "NYCE Door Hinge Sensor" - fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3011", deviceJoinName: "NYCE Door/Window Sensor" - fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3011", deviceJoinName: "NYCE Door/Window Sensor" - fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3014", deviceJoinName: "NYCE Tilt Sensor" - fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3014", deviceJoinName: "NYCE Tilt Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0500,0B05,FC02", outClusters: "", manufacturer: "sengled", model: "E1D-G73", deviceJoinName: "Sengled Element Door Sensor" + fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3010", deviceJoinName: "NYCE Open/Closed Sensor" //NYCE Door Hinge Sensor + fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3011", deviceJoinName: "NYCE Open/Closed Sensor" //NYCE Door/Window Sensor + fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3011", deviceJoinName: "NYCE Open/Closed Sensor" //NYCE Door/Window Sensor + fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3014", deviceJoinName: "NYCE Open/Closed Sensor" //NYCE Tilt Sensor + fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3014", deviceJoinName: "NYCE Open/Closed Sensor" //NYCE Tilt Sensor + fingerprint inClusters: "0000,0001,0003,0020,0500,0B05,FC02", outClusters: "", manufacturer: "sengled", model: "E1D-G73", deviceJoinName: "Sengled Open/Closed Sensor" //Sengled Element Door Sensor } tiles(scale: 2) { diff --git a/devicetypes/smartthings/open-closed-sensor.src/open-closed-sensor.groovy b/devicetypes/smartthings/open-closed-sensor.src/open-closed-sensor.groovy index a535d7f62f0..40c7197c515 100644 --- a/devicetypes/smartthings/open-closed-sensor.src/open-closed-sensor.groovy +++ b/devicetypes/smartthings/open-closed-sensor.src/open-closed-sensor.groovy @@ -16,7 +16,7 @@ metadata { capability "Contact Sensor" capability "Sensor" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0009,0500", outClusters: "0000" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0009,0500", outClusters: "0000", deviceJoinName: "Open/Closed Sensor" } // simulator metadata diff --git a/devicetypes/smartthings/orvibo-Moisture-Sensor.src/i18n/messages.properties b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/i18n/messages.properties new file mode 100755 index 00000000000..940a1bf1b79 --- /dev/null +++ b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/i18n/messages.properties @@ -0,0 +1,17 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Water Leak Sensor'''.zh-cn=海曼水浸探测器(HS3WL-E) +'''HEIMAN Water Leakage Sensor (HS3WL-E)'''.zh-cn=海曼水浸探测器(HS3WL-E) diff --git a/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy index 9901b866855..a08d137453d 100644 --- a/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy +++ b/devicetypes/smartthings/orvibo-Moisture-Sensor.src/orvibo-Moisture-Sensor.groovy @@ -31,8 +31,9 @@ metadata { capability "Health Check" capability "Battery" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,0009", outClusters: "0019", manufacturer: "Heiman", model: "2f077707a13f4120846e0775df7e2efe" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,0009", outClusters: "0019", manufacturer: "HEIMAN", model: "da2edf1ded0d44e1815d06f45ce02029" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001, 0009", outClusters: "0019", manufacturer: "Heiman", model: "2f077707a13f4120846e0775df7e2efe", deviceJoinName: "Orvibo Water Leak Sensor" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001, 0009", outClusters: "0019", manufacturer: "HEIMAN", model: "da2edf1ded0d44e1815d06f45ce02029", deviceJoinName: "Orvibo Water Leak Sensor" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001", manufacturer: "HEIMAN", model: "WaterSensor-N", deviceJoinName: "HEIMAN Water Leak Sensor" //HEIMAN Water Leakage Sensor (HS3WL-E) } simulator { @@ -112,11 +113,11 @@ def refresh() { def installed(){ log.debug "call installed()" - sendEvent(name: "checkInterval", value: 20 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + sendEvent(name: "checkInterval", value: 6 * 60 * 60 + 5 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) } def configure() { - sendEvent(name: "checkInterval", value: 20 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + sendEvent(name: "checkInterval", value: 6 * 60 * 60 + 5 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) log.debug "Configuring Reporting" def configCmds = [] @@ -148,4 +149,4 @@ def getBatteryPercentageResult(rawValue) { log.debug "${device.displayName} battery was ${result.value}%" result -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/orvibo-gas-detector.src/Orvibo-Gas-detector.groovy b/devicetypes/smartthings/orvibo-gas-detector.src/Orvibo-Gas-detector.groovy index a8f8281caec..86eee6ec47c 100644 --- a/devicetypes/smartthings/orvibo-gas-detector.src/Orvibo-Gas-detector.groovy +++ b/devicetypes/smartthings/orvibo-gas-detector.src/Orvibo-Gas-detector.groovy @@ -25,8 +25,9 @@ metadata { capability "Health Check" capability "Sensor" capability "Refresh" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0009", outClusters: "0019", manufacturer: "Heiman", model:"d0e857bfd54f4a12816295db3945a421", deviceJoinName: "欧瑞博 可燃气体报警器(SG21)" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0009", outClusters: "0019", manufacturer: "HEIMAN", model:"358e4e3e03c644709905034dae81433e", deviceJoinName: "欧瑞博 可燃气体报警器(SG21)" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0009", outClusters: "0019", manufacturer: "Heiman", model:"d0e857bfd54f4a12816295db3945a421", deviceJoinName: "Orvibo Gas Detector" //欧瑞博 可燃气体报警器(SG21) + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0009", outClusters: "0019", manufacturer: "HEIMAN", model:"358e4e3e03c644709905034dae81433e", deviceJoinName: "Orvibo Gas Detector" //欧瑞博 可燃气体报警器(SG21) + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500", outClusters: "0019", manufacturer: "HEIMAN", model:"GASSensor-N", deviceJoinName: "HEIMAN Gas Detector" //HEIMAN Gas Detector (HS3CG) } simulator { diff --git a/devicetypes/smartthings/orvibo-gas-detector.src/i18n/messages.properties b/devicetypes/smartthings/orvibo-gas-detector.src/i18n/messages.properties new file mode 100755 index 00000000000..d2c0a8e0fc7 --- /dev/null +++ b/devicetypes/smartthings/orvibo-gas-detector.src/i18n/messages.properties @@ -0,0 +1,18 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Gas Detector (HS3CG)'''.zh-cn=海曼燃气报警器(HS3CG) +'''HEIMAN Gas Detector'''.zh-cn=海曼燃气报警器(HS3CG) +'''Orvibo Gas Detector'''.zh-cn=欧瑞博 可燃气体报警器(SG21) \ No newline at end of file diff --git a/devicetypes/smartthings/ozom-smart-siren.src/i18n/messages.properties b/devicetypes/smartthings/ozom-smart-siren.src/i18n/messages.properties new file mode 100755 index 00000000000..cb6b452d9f8 --- /dev/null +++ b/devicetypes/smartthings/ozom-smart-siren.src/i18n/messages.properties @@ -0,0 +1,17 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Siren'''.zh-cn=海曼智能声光报警器 +'''HEIMAN Smart Siren'''.zh-cn=海曼智能声光报警器 diff --git a/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy b/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy index f3e67c53c61..a7447d5790f 100644 --- a/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy +++ b/devicetypes/smartthings/ozom-smart-siren.src/ozom-smart-siren.groovy @@ -18,14 +18,15 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus import physicalgraph.zigbee.zcl.DataType metadata { - definition(name: "Ozom Smart Siren", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-siren-8", ocfDeviceType: "x.com.st.d.siren") { + definition(name: "Ozom Smart Siren", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-siren-2", ocfDeviceType: "x.com.st.d.siren") { capability "Actuator" capability "Alarm" capability "Switch" capability "Configuration" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000,0003,0500,0502", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "SRAC_00.00.00.16TC", deviceJoinName: "Ozom Smart Siren" // Ozom Siren - SRAC-23ZBS + fingerprint profileId: "0104", inClusters: "0000,0003,0500,0502", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "SRAC_00.00.00.16TC", vid: "generic-siren-8", deviceJoinName: "Ozom Siren" // Ozom Siren - SRAC-23ZBS //Ozom Smart Siren + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0009,0500,0502", outClusters: "0003,0019", manufacturer: "Heiman", model: "WarningDevice", deviceJoinName: "HEIMAN Siren" //HEIMAN Smart Siren } tiles { @@ -50,13 +51,32 @@ private getATTRIBUTE_IAS_ZONE_STATUS() { 0x0002 } private getCOMMAND_IAS_WD_START_WARNING() { 0x00 } private getCOMMAND_DEFAULT_RESPONSE() { 0x0B } -def turnOffAlarmTile(){ +private getMODE_SIREN() { "13" } +private getMODE_STROBE() { "04" } +private getMODE_BOTH() { "17" } +private getMODE_OFF() { "00" } +private getSTROBE_DUTY_CYCLE() { "40" } +private getSTROBE_LEVEL() { "03" } + +private getALARM_OFF() { 0x00 } +private getALARM_SIREN() { 0x01 } +private getALARM_STROBE() { 0x02 } +private getALARM_BOTH() { 0x03 } + +def turnOffAlarmTile() { sendEvent(name: "alarm", value: "off") sendEvent(name: "switch", value: "off") } -def turnOnAlarmTile(){ - sendEvent(name: "alarm", value: "siren") +def turnOnAlarmTile(cmd) { + log.debug "turn on alarm tile ${cmd}" + if (cmd == ALARM_SIREN) { + sendEvent(name: "alarm", value: "siren") + } else if (cmd == ALARM_STROBE) { + sendEvent(name: "alarm", value: "strobe") + } else if (cmd == ALARM_BOTH) { + sendEvent(name: "alarm", value: "both") + } sendEvent(name: "switch", value: "on") } @@ -88,8 +108,8 @@ def parse(String description) { Boolean isSuccess = Integer.parseInt(data[-1], 16) == 0 Integer receivedCommand = Integer.parseInt(data[-2], 16) if (receivedCommand == COMMAND_IAS_WD_START_WARNING && isSuccess){ - if(state.alarmOn){ - turnOnAlarmTile() + if (state.alarmCmd != ALARM_OFF) { + turnOnAlarmTile(state.alarmCmd) runIn(state.lastDuration, turnOffAlarmTile) } else { turnOffAlarmTile() @@ -124,25 +144,61 @@ def configure() { return cmds } +def both() { + log.debug "both()" + startCmd(ALARM_BOTH) +} + def siren() { log.debug "siren()" - on() + startCmd(ALARM_SIREN) } -def on() { - log.debug "on()" +def strobe() { + log.debug "strobe()" + startCmd(ALARM_SIREN) +} + +def startCmd(cmd) { + log.debug "start command ${cmd}" - state.alarmOn = true + state.alarmCmd = cmd def warningDuration = state.maxDuration ? state.maxDuration : DEFAULT_MAX_DURATION state.lastDuration = warningDuration - // start warning, burglar mode, no strobe, siren very high - zigbee.command(IAS_WD_CLUSTER, COMMAND_IAS_WD_START_WARNING, "13", DataType.pack(warningDuration, DataType.UINT16), "00", "00") + def paramMode; + def paramDutyCycle = STROBE_DUTY_CYCLE; + def paramStrobeLevel = STROBE_LEVEL; + if (cmd == ALARM_SIREN) { + paramMode = MODE_SIREN + paramDutyCycle = "00" + paramStrobeLevel = "00" + } else if (cmd == ALARM_STROBE) { + paramMode = MODE_STROBE + } else if (cmd == ALARM_BOTH) { + paramMode = MODE_BOTH + } + + zigbee.command(IAS_WD_CLUSTER, COMMAND_IAS_WD_START_WARNING, paramMode, DataType.pack(warningDuration, DataType.UINT16), paramDutyCycle, paramStrobeLevel) +} + +def on() { + log.debug "on()" + + if (isOzomSiren()) { + siren() + } else { + both() + } } def off() { log.debug "off()" - state.alarmOn = false + state.alarmCmd = ALARM_OFF zigbee.command(IAS_WD_CLUSTER, COMMAND_IAS_WD_START_WARNING, "00", "0000", "00", "00") } + +private isOzomSiren() { + device.getDataValue("manufacturer") == "ClimaxTechnology" +} diff --git a/devicetypes/smartthings/philio-multiple-sound-siren.src/philio-multiple-sound-siren.groovy b/devicetypes/smartthings/philio-multiple-sound-siren.src/philio-multiple-sound-siren.groovy index 805b9184616..bdfe84310c5 100644 --- a/devicetypes/smartthings/philio-multiple-sound-siren.src/philio-multiple-sound-siren.groovy +++ b/devicetypes/smartthings/philio-multiple-sound-siren.src/philio-multiple-sound-siren.groovy @@ -29,7 +29,7 @@ metadata { command "test" - fingerprint mfr: "013C", prod: "0004", model: "000A", deviceJoinName: "Philio Multiple Sound Siren PSE02" + fingerprint mfr: "013C", prod: "0004", model: "000A", deviceJoinName: "Philio Siren" //Philio Multiple Sound Siren PSE02 } simulator { diff --git a/devicetypes/smartthings/plant-link.src/plant-link.groovy b/devicetypes/smartthings/plant-link.src/plant-link.groovy index e3114e37556..d32419b6649 100644 --- a/devicetypes/smartthings/plant-link.src/plant-link.groovy +++ b/devicetypes/smartthings/plant-link.src/plant-link.groovy @@ -23,8 +23,8 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000,0003,0405,FC08", outClusters: "0003" - fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0B04", outClusters: "0003", manufacturer: "", model: "", deviceJoinName: "OSO Technologies PlantLink Soil Moisture Sensor" + fingerprint profileId: "0104", inClusters: "0000,0003,0405,FC08", outClusters: "0003", deviceJoinName: "Plant Link Humidity Sensor" + fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0B04", outClusters: "0003", manufacturer: "", model: "", deviceJoinName: "Plant Link Humidity Sensor" //OSO Technologies PlantLink Soil Moisture Sensor } tiles { diff --git a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy index 4815f241875..e836a7a42b6 100644 --- a/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy +++ b/devicetypes/smartthings/qubino-flush-thermostat.src/qubino-flush-thermostat.groovy @@ -28,7 +28,7 @@ metadata { command "changeMode" - fingerprint mfr: "0159", prod: "0005", model: "0054", deviceJoinName: "Qubino Flush On/Off Thermostat 2" + fingerprint mfr: "0159", prod: "0005", model: "0054", deviceJoinName: "Qubino Thermostat" //Qubino Flush On/Off Thermostat 2 } tiles(scale: 2) { @@ -331,9 +331,9 @@ private getCurrentSetpointType() { } private getMaxSetpointTemperature() { - temperatureScale == 'C' ? 40 : 104 + temperatureScale == 'C' ? 80 : 176 } private getMinSetpointTemperature() { - temperatureScale == 'C' ? -12 : 11 + temperatureScale == 'C' ? -25 : -13 } \ No newline at end of file diff --git a/devicetypes/smartthings/rgbw-light.src/rgbw-light.groovy b/devicetypes/smartthings/rgbw-light.src/rgbw-light.groovy index 290d64c4244..02f2496eba0 100644 --- a/devicetypes/smartthings/rgbw-light.src/rgbw-light.groovy +++ b/devicetypes/smartthings/rgbw-light.src/rgbw-light.groovy @@ -16,6 +16,14 @@ * Date: 2015-7-12 */ +private getAEOTEC_LED6_MFR() { "0371" } +private getAEOTEC_LED6_PROD_US() { "0103" } +private getAEOTEC_LED6_PROD_EU() { "0003" } +private getAEOTEC_LED6_MODEL() { "0002" } + +private getAEOTEC_LED_STRIP_MFR() { "0086" } +private getAEOTEC_LED_STRIP_MODEL() { "0079" } + metadata { definition (name: "RGBW Light", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb") { capability "Switch Level" @@ -27,15 +35,50 @@ metadata { capability "Sensor" capability "Health Check" - command "reset" - - fingerprint inClusters: "0x26,0x33" - fingerprint inClusters: "0x33" - fingerprint mfr: "0086", prod: "0103", model: "0079", deviceJoinName: "Aeotec LED Strip" //US - fingerprint mfr: "0086", prod: "0003", model: "0079", deviceJoinName: "Aeotec LED Strip" //EU - fingerprint mfr: "0086", prod: "0003", model: "0062", deviceJoinName: "Aeotec LED Bulb" //EU - fingerprint mfr: "0086", prod: "0103", model: "0062", deviceJoinName: "Aeotec LED Bulb" //US - fingerprint mfr: "0300", prod: "0003", model: "0003", deviceJoinName: "ilumin RGBW Bulb" + /* + * Relevant device types: + * + * * 0x11 GENERIC_TYPE_SWITCH_MULTILEVEL + * * 0x01 SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL + * * 0x02 SPECIFIC_TYPE_COLOR_TUNABLE_MULTILEVEL + * + * Plausible command classes we might see in a color light bulb: + * + * 0x98 COMMAND_CLASS_SECURITY + * 0x5E COMMAND_CLASS_ZWAVEPLUS_INFO_V2 + * 0x20 COMMAND_CLASS_BASIC + * 0x26 COMMAND_CLASS_SWITCH_MULTILEVEL + * 0X27 COMMAND_CLASS_SWITCH_ALL + * 0x33 COMMAND_CLASS_SWITCH_COLOR + * 0x70 COMMAND_CLASS_CONFIGURATION + * 0x73 COMMAND_CLASS_POWERLEVEL + * + * Here are the command classes used by this driver that we can fingerprint against: + * + * * 0x26 COMMAND_CLASS_SWITCH_MULTILEVEL -> yes, it is dimmable + * * 0x33 COMMAND_CLASS_SWITCH_COLOR -> yes, it has color control + */ + + // dimmable, color control + fingerprint inClusters: "0x26,0x33", deviceJoinName: "Light" //Z-Wave RGBW Bulb + + // GENERIC_TYPE_SWITCH_MULTILEVEL:SPECIFIC_TYPE_POWER_SWITCH_MULTILEVEL + // dimmable, color control + fingerprint deviceId: "0x1101", inClusters: "0x26,0x33", deviceJoinName: "Light" //Z-Wave RGBW Bulb + + // GENERIC_TYPE_SWITCH_MULTILEVEL:SPECIFIC_TYPE_COLOR_TUNABLE_MULTILEVEL + // dimmable, color control + fingerprint deviceId: "0x1102", inClusters: "0x26,0x33", deviceJoinName: "Light" //Z-Wave RGBW Bulb + + // Manufacturer and model-specific fingerprints. + fingerprint mfr: "0086", prod: "0103", model: "0079", deviceJoinName: "Aeotec Light", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-3000K-8000K" //US //Aeotec LED Strip + fingerprint mfr: "0086", prod: "0003", model: "0079", deviceJoinName: "Aeotec Light", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-3000K-8000K" //EU //Aeotec LED Strip + fingerprint mfr: "0086", prod: "0103", model: "0062", deviceJoinName: "Aeotec Light" //US //Aeotec LED Bulb + fingerprint mfr: "0086", prod: "0003", model: "0062", deviceJoinName: "Aeotec Light" //EU //Aeotec LED Bulb + fingerprint mfr: AEOTEC_LED6_MFR, prod: AEOTEC_LED6_PROD_US, model: AEOTEC_LED6_MODEL, deviceJoinName: "Aeotec Light" //US //Aeotec LED Bulb 6 + fingerprint mfr: AEOTEC_LED6_MFR, prod: AEOTEC_LED6_PROD_EU, model: AEOTEC_LED6_MODEL, deviceJoinName: "Aeotec Light" //EU //Aeotec LED Bulb 6 + fingerprint mfr: "0300", prod: "0003", model: "0003", deviceJoinName: "ilumin Light" //ilumin RGBW Bulb + fingerprint mfr: "031E", prod: "0005", model: "0001", deviceJoinName: "ilumin Light" //ilumin RGBW Bulb } simulator { @@ -60,18 +103,39 @@ metadata { } } - standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { - state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single" - } - controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2700..6500)") { state "colorTemperature", action:"color temperature.setColorTemperature" } main(["switch"]) - details(["switch", "levelSliderControl", "rgbSelector", "colorTempSliderControl", "reset"]) + details(["switch", "levelSliderControl", "colorTempSliderControl"]) } +private getCOLOR_TEMP_MIN() { isAeotecLedStrip() ? 3000 : 2700 } +private getCOLOR_TEMP_MAX() { isAeotecLedStrip() ? 8000 : 6500 } +// For Z-Wave devices, we control illumination by crossfading the cold and warm +// white channels. But for devices that only have single cold or warm white +// illumination (as with many RGBW LED strips), we cannot dim either white +// channel to 0, as this will then completely turn off illumination. +// Therefore, we lower-bound both white channels to 1. This will have no +// perceptible impact for devices that actually support white temperature +// cross-fading, but will keep devices that do not doing something sane from +// the user perspective, which is to modify intensity for the single white +private getWHITE_MIN() { 1 } // min for Z-Wave coldWhite and warmWhite paramaeters +private getWHITE_MAX() { 255 } // max for Z-Wave coldWhite and warmWhite paramaeters +private getCOLOR_TEMP_DIFF() { COLOR_TEMP_MAX - COLOR_TEMP_MIN } +private getRED() { "red" } +private getGREEN() { "green" } +private getBLUE() { "blue" } +private getWARM_WHITE() { "warmWhite" } +private getCOLD_WHITE() { "coldWhite" } +private getRGB_NAMES() { [RED, GREEN, BLUE] } +private getWHITE_NAMES() { [WARM_WHITE, COLD_WHITE] } +private getCOLOR_NAMES() { RGB_NAMES + WHITE_NAMES } +private getSWITCH_VALUE_ON() { 0xFF } // Per Z-Wave, this multilevel switch value commands state-transition to on. This will restore the most-recent non-zero value cached in the device. +private getSWITCH_VALUE_OFF() { 0 } // Per Z-Wave, this multilevel switch value commands state-transition to off. This will not clobber the most-recent non-zero value cached in the device. +private BOUND(x, floor, ceiling) { Math.max(Math.min(x, ceiling), floor) } + def updated() { log.debug "updated().." response(refresh()) @@ -79,10 +143,12 @@ def updated() { def installed() { log.debug "installed()..." - state.colorReceived = ["red": null, "green": null, "blue": null, "warmWhite": null, "coldWhite": null] - sendEvent(name: "checkInterval", value: 1860, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "0"]) - sendEvent(name: "level", value: 100, unit: "%") - response(refresh()) + sendEvent(name: "checkInterval", value: 1860, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "level", value: 100, unit: "%", displayed: false) + sendEvent(name: "colorTemperature", value: COLOR_TEMP_MIN, displayed: false) + sendEvent(name: "color", value: "#000000", displayed: false) + sendEvent(name: "hue", value: 0, displayed: false) + sendEvent(name: "saturation", value: 0, displayed: false) } def parse(description) { @@ -115,39 +181,15 @@ def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelR def zwaveEvent(physicalgraph.zwave.commands.switchcolorv3.SwitchColorReport cmd) { log.debug "got SwitchColorReport: $cmd" - if (!state.colorReceived) - state.colorReceived = ["red": null, "green": null, "blue": null, "warmWhite": null, "coldWhite": null] - state.colorReceived[cmd.colorComponent] = cmd.value def result = [] - def rgbNames = ["red", "green", "blue"] - def tempNames = ["warmWhite", "coldWhite"] - // Check if we got all the RGB color components - if (rgbNames.every { state.colorReceived[it] != null }) { - def colors = rgbNames.collect { state.colorReceived[it] } - log.debug "colors: $colors" - // Send the color as hex format - def hexColor = "#" + colors.collect { Integer.toHexString(it).padLeft(2, "0") }.join("") - result << createEvent(name: "color", value: hexColor) - // Send the color as hue and saturation - def hsv = rgbToHSV(*colors) - result << createEvent(name: "hue", value: hsv.hue) - result << createEvent(name: "saturation", value: hsv.saturation) - // Reset the values - rgbNames.collect { state.colorReceived[it] = null} - } - // Check if we got all the color temperature values - if (tempNames.every { state.colorReceived[it] != null}) { - def warmWhite = state.colorReceived["warmWhite"] - def coldWhite = state.colorReceived["coldWhite"] - log.debug "warmWhite: $warmWhite, coldWhite: $coldWhite" - // When the device is first installed, warmWhite == coldWhite == 255 - // so default to mid-range color temp. - def colorTemp = COLOR_TEMP_MIN + (COLOR_TEMP_DIFF / 2) - if (warmWhite != coldWhite) - colorTemp = (COLOR_TEMP_MAX - (COLOR_TEMP_DIFF * warmWhite) / 255) as Integer - result << createEvent(name: "colorTemperature", value: colorTemp) - // Reset the values - tempNames.collect { state.colorReceived[it] = null } + if (state.staged != null && cmd.colorComponent in RGB_NAMES) { + // We use this as a callback from our color setter. + // Emit our color update event with our staged state. + state.staged.subMap("hue", "saturation", "color").each{ k, v -> result << createEvent(name: k, value: v) } + } else if (state.staged != null && cmd.colorComponent in WHITE_NAMES) { + // We use this as a callback from our temperature setter. + // Emit our color temperature update event with our staged state. + state.staged.subMap("colorTemperature").each{ k, v -> result << createEvent(name: k, value: v) } } result } @@ -161,10 +203,6 @@ private dimmerEvents(physicalgraph.zwave.Command cmd) { return result } -def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) { - response(command(zwave.switchMultilevelV1.switchMultilevelGet())) -} - def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { def encapsulatedCommand = cmd.encapsulatedCommand() if (encapsulatedCommand) { @@ -186,16 +224,28 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { [linkText: linkText, descriptionText: "$linkText: $cmd", displayed: false] } -def buildOffOnEvent(cmd){ - [zwave.basicV1.basicSet(value: cmd), zwave.switchMultilevelV3.switchMultilevelGet()] +private emitMultiLevelSet(level, duration=1) { + log.debug "setLevel($level, $duration)" + duration = duration < 128 ? duration : 127 + Math.round(duration / 60) // See Z-Wave duration encodinbg + duration = Math.min(duration, 0xFE) // 0xFF is a special code for factory default; bound to 0xFE + def tcallback = Math.min(duration * 1000 + 2500, 12000) // how long should we wait to read back? we can't wait forever + commands([ + zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: duration), + zwave.switchMultilevelV3.switchMultilevelGet(), + ], tcallback) } def on() { - commands(buildOffOnEvent(0xFF), 3500) + emitMultiLevelSet(SWITCH_VALUE_ON) } def off() { - commands(buildOffOnEvent(0x00), 3500) + emitMultiLevelSet(SWITCH_VALUE_OFF) +} + +def setLevel(level, duration=1) { + level = BOUND(level, 1, 99) // See Z-Wave level encoding + emitMultiLevelSet(level, duration) } def refresh() { @@ -207,19 +257,6 @@ def ping() { refresh() } -def setLevel(level) { - setLevel(level, 1) -} - -def setLevel(level, duration) { - log.debug "setLevel($level, $duration)" - if(level > 99) level = 99 - commands([ - zwave.switchMultilevelV3.switchMultilevelSet(value: level, dimmingDuration: duration), - zwave.switchMultilevelV3.switchMultilevelGet(), - ], (duration && duration < 12) ? (duration * 1000) : 3500) -} - def setSaturation(percent) { log.debug "setSaturation($percent)" setColor(saturation: percent) @@ -232,53 +269,109 @@ def setHue(value) { def setColor(value) { log.debug "setColor($value)" - def result = [] + def rgb + if (state.staged == null) { + state.staged = [:] + } if (value.hex) { - def c = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) } - result << zwave.switchColorV3.switchColorSet(red:c[0], green:c[1], blue:c[2], warmWhite:0, coldWhite:0) + state.staged << [color: value.hex] // stage ST RGB color attribute + def hsv = colorUtil.hexToHsv(value.hex) // convert to HSV + state.staged << [hue: hsv[0], saturation: hsv[1]] // stage ST hue and saturation attributes + rgb = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) } // separate RGB elements for zwave setter } else { - def rgb = huesatToRGB(value.hue, value.saturation) - result << zwave.switchColorV3.switchColorSet(red: rgb[0], green: rgb[1], blue: rgb[2], warmWhite:0, coldWhite:0) + state.staged << value.subMap("hue", "saturation") // stage ST hue and saturation attributes + def hex = colorUtil.hsvToHex(Math.round(value.hue) as int, Math.round(value.saturation) as int) // convert to hex + state.staged << [color: hex] // stage ST RGB color attribute + rgb = colorUtil.hexToRgb(hex) // separate RGB elements for zwave setter } - if (device.currentValue("switch") != "on") { - result << zwave.basicV1.basicSet(value: 0xFF) - result << zwave.switchMultilevelV3.switchMultilevelGet() + commands([zwave.switchColorV3.switchColorSet(red: rgb[0], green: rgb[1], blue: rgb[2], warmWhite: 0, coldWhite: 0), + zwave.switchColorV3.switchColorGet(colorComponent: RGB_NAMES[0]), // event-publish callback is on any of the RGB responses, so only need to GET one of these + ], 3500) +} + +private emitTemperatureSet(temp, cmds) { + // Restrict temp to legal bounds. + temp = BOUND(temp, COLOR_TEMP_MIN, COLOR_TEMP_MAX) + // Add our staging dictionary to state. + if (state.staged == null) { + state.staged = [:] } - result += queryAllColors() + // Stage ST colorTemperature attribute. + state.staged << [colorTemperature: temp] + // Emit our command. Follow up with callback-trigger getter. Our + // event-publish callback is on any of the while-level responses, + // so we only need to GET one of these these. Make sure that we + // only have delay immediately before the callback trigger getter. + def prologue = cmds.init() // grab all but last + def epilogue = [] << cmds.last() // grab last + epilogue << zwave.switchColorV3.switchColorGet(colorComponent: WHITE_NAMES[0]) // append callback get + def rv = prologue.size() > 0 ? commands(prologue, 0) : [] // collect formatted prologue; check for empty; empty is OK, but can't be passed to commands() + rv << commands(epilogue, 3500) // collect formatted epilogue; only delay immediately before callback getter + return rv // return formatted command array to execute +} - commands(result) +private tempToZwaveWarmWhite(temp) { + temp = BOUND(temp, COLOR_TEMP_MIN, COLOR_TEMP_MAX) + def warmValue = ((COLOR_TEMP_MAX - temp) / COLOR_TEMP_DIFF * WHITE_MAX) as Integer + warmValue = Math.max(WHITE_MIN, warmValue) + warmValue } -private getCOLOR_TEMP_MAX() { 6500 } -private getCOLOR_TEMP_MIN() { 2700 } -private getCOLOR_TEMP_DIFF() { COLOR_TEMP_MAX - COLOR_TEMP_MIN } +private tempToZwaveColdWhite(temp) { + def coldValue = (WHITE_MAX - tempToZwaveWarmWhite(temp)) + coldValue = Math.max(WHITE_MIN, coldValue) + coldValue +} + +private setZwaveColorTemperature(temp) { + def warmValue = tempToZwaveWarmWhite(temp) + def coldValue = tempToZwaveColdWhite(temp) + emitTemperatureSet(temp, [zwave.switchColorV3.switchColorSet(red: 0, green: 0, blue: 0, warmWhite: warmValue, coldWhite: coldValue)]) +} + +private setAeotecLed6ColorTemperature(temp) { + temp = BOUND(temp, COLOR_TEMP_MIN, COLOR_TEMP_MAX) + def warmValue = temp < 5000 ? 255 : 0 + def coldValue = temp >= 5000 ? 255 : 0 + def WARM_WHITE_CONFIG = 0x51 + def COLD_WHITE_CONFIG = 0x52 + def parameterNumber = temp < 5000 ? WARM_WHITE_CONFIG : COLD_WHITE_CONFIG + // The Aeotec bulbs require special handling for temperature crossfade + // due to their imposition of precedence for warm white (highest + // precedence) and cold white (next highest precedence) channels, + // and due to their use of manufacturer specific temperature config + // commands. + // + // To be successful, we must: + // + // * set inverse channel intensity to 0 and desired channel to 255 - note this clobbers temp + // * then apply desired cold or warm temp with Aeotec-specific config 0x51 or 0x52 + emitTemperatureSet(temp, [zwave.switchColorV3.switchColorSet(red: 0, green: 0, blue: 0, warmWhite: warmValue, coldWhite: coldValue), + zwave.configurationV1.configurationSet([parameterNumber: parameterNumber, size: 2, scaledConfigurationValue: temp])]) +} + +def isAeotecLed6() { + ( (zwaveInfo?.mfr?.equals(AEOTEC_LED6_MFR) && zwaveInfo?.prod?.equals(AEOTEC_LED6_PROD_US) && zwaveInfo?.model?.equals(AEOTEC_LED6_MODEL)) + || (zwaveInfo?.mfr?.equals(AEOTEC_LED6_MFR) && zwaveInfo?.prod?.equals(AEOTEC_LED6_PROD_EU) && zwaveInfo?.model?.equals(AEOTEC_LED6_MODEL))) +} + +def isAeotecLedStrip(){ + (zwaveInfo?.mfr?.equals(AEOTEC_LED_STRIP_MFR) && zwaveInfo?.model?.equals(AEOTEC_LED_STRIP_MODEL)) +} def setColorTemperature(temp) { - if(temp > COLOR_TEMP_MAX) - temp = COLOR_TEMP_MAX - else if(temp < COLOR_TEMP_MIN) - temp = COLOR_TEMP_MIN log.debug "setColorTemperature($temp)" - def warmValue = ((COLOR_TEMP_MAX - temp) / COLOR_TEMP_DIFF * 255) as Integer - def coldValue = 255 - warmValue - def result = [] - result << zwave.switchColorV3.switchColorSet(red: 0, green: 0, blue: 0, warmWhite: warmValue, coldWhite: coldValue) - if (device.currentValue("switch") != "on") { - result << zwave.basicV1.basicSet(value: 0xFF) - result << zwave.switchMultilevelV3.switchMultilevelGet() + if (isAeotecLed6()) { + // Call the special Aeotec LED Bulb 6 setter. + // The default Z-Wave temperature setter won't work for this bulb. + setAeotecLed6ColorTemperature(temp) + } else { + setZwaveColorTemperature(temp) } - result += queryAllColors() - commands(result) } private queryAllColors() { - def colors = ["red", "green", "blue", "warmWhite", "coldWhite"] - colors.collect { zwave.switchColorV3.switchColorGet(colorComponent: it) } -} - -def reset() { - log.debug "reset()" - setColorTemperature(COLOR_TEMP_MIN + (COLOR_TEMP_DIFF / 2)) + COLOR_NAMES.collect { zwave.switchColorV3.switchColorGet(colorComponent: it) } } private secEncap(physicalgraph.zwave.Command cmd) { @@ -292,7 +385,7 @@ private crcEncap(physicalgraph.zwave.Command cmd) { private command(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s") || state.sec == 1) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { cmd.format() @@ -302,14 +395,3 @@ private command(physicalgraph.zwave.Command cmd) { private commands(commands, delay=200) { delayBetween(commands.collect{ command(it) }, delay) } - -def rgbToHSV(red, green, blue) { - def hex = colorUtil.rgbToHex(red as int, green as int, blue as int) - def hsv = colorUtil.hexToHsv(hex) - return [hue: hsv[0], saturation: hsv[1], value: hsv[2]] -} - -def huesatToRGB(hue, sat) { - def color = colorUtil.hsvToHex(Math.round(hue) as int, Math.round(sat) as int) - return colorUtil.hexToRgb(color) -} \ No newline at end of file diff --git a/devicetypes/smartthings/secure-dimmer.src/secure-dimmer.groovy b/devicetypes/smartthings/secure-dimmer.src/secure-dimmer.groovy index d24cd3d79d3..9f3208688fa 100644 --- a/devicetypes/smartthings/secure-dimmer.src/secure-dimmer.groovy +++ b/devicetypes/smartthings/secure-dimmer.src/secure-dimmer.groovy @@ -19,7 +19,7 @@ metadata { capability "Refresh" capability "Sensor" - fingerprint deviceId: "0x11", inClusters: "0x98" + fingerprint deviceId: "0x11", inClusters: "0x98", deviceJoinName: "Dimmer Switch" } simulator { diff --git a/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy b/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy index f264c03f2d6..564ace2cf9f 100644 --- a/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy +++ b/devicetypes/smartthings/smartalert-siren.src/smartalert-siren.groovy @@ -25,8 +25,8 @@ metadata { command "test" - fingerprint deviceId: "0x1100", inClusters: "0x26,0x71" - fingerprint mfr:"0084", prod:"0313", model:"010B", deviceJoinName: "FortrezZ Siren Strobe Alarm" + fingerprint deviceId: "0x1100", inClusters: "0x26,0x71", deviceJoinName: "Siren" + fingerprint mfr:"0084", prod:"0313", model:"010B", deviceJoinName: "FortrezZ Siren" //FortrezZ Siren Strobe Alarm } simulator { diff --git a/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy b/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy index ce5e4d31c90..dce10eb7428 100644 --- a/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy +++ b/devicetypes/smartthings/smartpower-dimming-outlet.src/smartpower-dimming-outlet.groovy @@ -27,7 +27,7 @@ metadata { capability "Outlet" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-ZHAC" + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-ZHAC", deviceJoinName: "Centralite Dimmer Switch" } diff --git a/devicetypes/smartthings/smartpower-outlet-v1.src/smartpower-outlet-v1.groovy b/devicetypes/smartthings/smartpower-outlet-v1.src/smartpower-outlet-v1.groovy index 8a1f71ec399..82875fd0d82 100644 --- a/devicetypes/smartthings/smartpower-outlet-v1.src/smartpower-outlet-v1.groovy +++ b/devicetypes/smartthings/smartpower-outlet-v1.src/smartpower-outlet-v1.groovy @@ -6,7 +6,7 @@ metadata { capability "Sensor" capability "Outlet" - fingerprint profileId: "0104", inClusters: "0006, 0004, 0003, 0000, 0005", outClusters: "0019", manufacturer: "Compacta International, Ltd", model: "ZBMPlug15", deviceJoinName: "SmartPower Outlet V1" + fingerprint profileId: "0104", inClusters: "0006, 0004, 0003, 0000, 0005", outClusters: "0019", manufacturer: "Compacta International, Ltd", model: "ZBMPlug15", deviceJoinName: "Smartenit Outlet" //SmartPower Outlet V1 } // simulator metadata diff --git a/devicetypes/smartthings/smartpower-outlet.src/i18n/messages.properties b/devicetypes/smartthings/smartpower-outlet.src/i18n/messages.properties index 51d9d397dc4..e1fd1ee0a2c 100644 --- a/devicetypes/smartthings/smartpower-outlet.src/i18n/messages.properties +++ b/devicetypes/smartthings/smartpower-outlet.src/i18n/messages.properties @@ -14,6 +14,8 @@ # Korean (ko) # Device Preferences '''Give your device a name'''.ko=기기 이름 설정 +'''SmartThings Outlet'''.ko= 스마트 플러그 +'''Centralite Outlet'''.ko= 스마트 플러그 '''Outlet'''.ko= 스마트 플러그 # Events descriptionText '''{{ device.displayName }} is On'''.ko={{ device.displayName }} 켜짐 diff --git a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy index 1d1fb7d814f..c90836b4906 100644 --- a/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy +++ b/devicetypes/smartthings/smartpower-outlet.src/smartpower-outlet.groovy @@ -25,15 +25,17 @@ metadata { capability "Health Check" capability "Outlet" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019" - fingerprint profileId: "0104", inClusters: "0000,0003,0006,0009,0B04", outClusters: "0019", manufacturer: "Samjin", model: "outlet", deviceJoinName: "Outlet" - fingerprint profileId: "0010", inClusters: "0000 0003 0004 0005 0006 0008 0702 0B05", outClusters: "0019", manufacturer: "innr", model: "SP 120", deviceJoinName: "Innr Smart Plug" - fingerprint profileId: "0104", inClusters: "0000,0002,0003,0004,0005,0006,0009,0B04,0702", outClusters: "0019,000A,0003,0406", manufacturer: "Aurora", model: "SmartPlug51AU", deviceJoinName: "Aurora SmartPlug" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0702,0B04,0B05,FC03", outClusters: "0019", manufacturer: "CentraLite", model: "3210-L", deviceJoinName: "Iris Smart Plug" + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "SmartThings Outlet" //Outlet + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "SmartThings Outlet" //Outlet + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Centralite Outlet" //Outlet + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "SmartThings Outlet", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartPower_Outlet" //Outlet + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", deviceJoinName: "Outlet" + fingerprint profileId: "0104", inClusters: "0000,0003,0006,0009,0B04", outClusters: "0019", manufacturer: "Samjin", model: "outlet", deviceJoinName: "SmartThings Outlet" //Outlet + fingerprint profileId: "0010", inClusters: "0000 0003 0004 0005 0006 0008 0702 0B05", outClusters: "0019", manufacturer: "innr", model: "SP 120", deviceJoinName: "Innr Outlet" //Innr Smart Plug + fingerprint profileId: "0104", inClusters: "0000,0002,0003,0004,0005,0006,0009,0B04,0702", outClusters: "0019,000A,0003,0406", manufacturer: "Aurora", model: "SmartPlug51AU", deviceJoinName: "Aurora Outlet" //Aurora SmartPlug + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0B04", outClusters: "0019", manufacturer: "Aurora", model: "SingleSocket50AU", deviceJoinName: "Aurora Outlet" //Aurora SmartPlug + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0702,0B04,0B05,FC03", outClusters: "0019", manufacturer: "CentraLite", model: "3210-L", deviceJoinName: "Iris Outlet" //Iris Smart Plug + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0B04,0B05,0702", outClusters: "0003,000A,0B05,0019", manufacturer: " Sercomm Corp.", model: "SZ-ESW01-AU", deviceJoinName: "Sercomm Outlet" //Sercomm Smart Power Plug } // simulator metadata @@ -87,8 +89,10 @@ def parse(String description) { if (event) { if (event.name == "power") { - def value = (event.value as Integer) / 10 - event = createEvent(name: event.name, value: value, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true) + def div = device.getDataValue("divisor") + div = div ? (div as int) : 10 + def powerValue = (event.value as Integer)/div + event = createEvent(name: event.name, value: powerValue, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true) } else if (event.name == "switch") { def descriptionText = event.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off' event = createEvent(name: event.name, value: event.value, descriptionText: descriptionText, translatable: true) @@ -131,6 +135,11 @@ def refresh() { } def configure() { + // Setting proper divisor for Aurora AOne 13A Smart Plug + def deviceModel = device.getDataValue("model") + def divisorValue = deviceModel == "SingleSocket50AU" ? "1" : "10" + device.updateDataValue("divisor", divisorValue) + // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time) // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) diff --git a/devicetypes/smartthings/smartsense-button.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-button.src/i18n/messages.properties old mode 100644 new mode 100755 index 58a68bd439c..8aa53ce0472 --- a/devicetypes/smartthings/smartsense-button.src/i18n/messages.properties +++ b/devicetypes/smartthings/smartsense-button.src/i18n/messages.properties @@ -12,6 +12,107 @@ # License for the specific language governing permissions and limitations # under the License. +# Korean +'''Button'''.ko=스마트 버튼 + # Chinese '''Button'''.zh-cn=无线开关 '''Button'''.zh-hk=Button +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy b/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy old mode 100644 new mode 100755 index 5f1cc89bf0b..209c08ad376 --- a/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy +++ b/devicetypes/smartthings/smartsense-button.src/smartsense-button.groovy @@ -43,7 +43,7 @@ metadata { ]) } section { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } } @@ -140,7 +140,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) map.unit = getTemperatureScale() } map.descriptionText = getTemperatureScale() == 'C' ? "${ device.displayName } was ${ map.value }°C" : "${ device.displayName } was ${ map.value }°F" diff --git a/devicetypes/smartthings/smartsense-garage-door-multi.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-garage-door-multi.src/i18n/messages.properties new file mode 100644 index 00000000000..1a64327c7c5 --- /dev/null +++ b/devicetypes/smartthings/smartsense-garage-door-multi.src/i18n/messages.properties @@ -0,0 +1,112 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy b/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy index cffa8d9d9af..e33f187f81e 100644 --- a/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy +++ b/devicetypes/smartthings/smartsense-garage-door-multi.src/smartsense-garage-door-multi.groovy @@ -25,8 +25,6 @@ metadata { capability "Sensor" capability "Battery" - attribute "status", "string" - attribute "door", "string" } simulator { @@ -48,18 +46,12 @@ metadata { } tiles(scale: 2) { - multiAttributeTile(name:"status", type: "generic", width: 6, height: 4){ - tileAttribute ("device.status", key: "PRIMARY_CONTROL") { - attributeState "closed", label:'${name}', icon:"st.doors.garage.garage-closed", backgroundColor:"#00A0DC", nextState:"opening" - attributeState "open", label:'${name}', icon:"st.doors.garage.garage-open", backgroundColor:"#e86d13", nextState:"closing" - attributeState "opening", label:'${name}', icon:"st.doors.garage.garage-opening", backgroundColor:"#e86d13" - attributeState "closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC" + multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){ + tileAttribute ("device.contact", key: "PRIMARY_CONTROL") { + attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13" + attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00a0dc" } } - standardTile("contact", "device.contact", width: 2, height: 2) { - state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13") - state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC") - } standardTile("acceleration", "device.acceleration", decoration: "flat", width: 2, height: 2) { state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC") state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff") @@ -74,12 +66,12 @@ metadata { state "battery", label:'${currentValue}% battery', unit:"" } - main(["status", "contact", "acceleration"]) - details(["status", "contact", "acceleration", "temperature", "3axis", "battery"]) + main(["contact", "acceleration"]) + details(["contact", "acceleration", "temperature", "3axis", "battery"]) } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } } @@ -217,14 +209,10 @@ private List parseOrientationMessage(String description) { if (absValueZ > 825) { results << createEvent(name: "contact", value: "open", unit: "") - results << createEvent(name: "status", value: "open", unit: "") - results << createEvent(name: "door", value: "open", unit: "") log.debug "STATUS: open" } else if (absValueZ < 100) { results << createEvent(name: "contact", value: "closed", unit: "") - results << createEvent(name: "status", value: "closed", unit: "") - results << createEvent(name: "door", value: "closed", unit: "") log.debug "STATUS: closed" } @@ -278,9 +266,7 @@ private getTempResult(part, description) { def temperatureScale = getTemperatureScale() def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale) if (tempOffset) { - def offset = tempOffset as int - def v = value as int - value = v + offset + value = new BigDecimal((value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } def linkText = getLinkText(device) def descriptionText = "$linkText was $value°$temperatureScale" diff --git a/devicetypes/smartthings/smartsense-garage-door-sensor-button.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-garage-door-sensor-button.src/i18n/messages.properties new file mode 100644 index 00000000000..1a64327c7c5 --- /dev/null +++ b/devicetypes/smartthings/smartsense-garage-door-sensor-button.src/i18n/messages.properties @@ -0,0 +1,112 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-garage-door-sensor-button.src/smartsense-garage-door-sensor-button.groovy b/devicetypes/smartthings/smartsense-garage-door-sensor-button.src/smartsense-garage-door-sensor-button.groovy index 3c365993b45..4521db28a53 100644 --- a/devicetypes/smartthings/smartsense-garage-door-sensor-button.src/smartsense-garage-door-sensor-button.groovy +++ b/devicetypes/smartthings/smartsense-garage-door-sensor-button.src/smartsense-garage-door-sensor-button.groovy @@ -88,7 +88,7 @@ metadata { } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } } @@ -298,9 +298,7 @@ private getTempResult(part, description) { def temperatureScale = getTemperatureScale() def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale) if (tempOffset) { - def offset = tempOffset as int - def v = value as int - value = v + offset + value = new BigDecimal((value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } def linkText = getLinkText(device) def descriptionText = "$linkText was $value°$temperatureScale" diff --git a/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties index d0e1ade564a..ad39b4c7e21 100644 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/i18n/messages.properties @@ -12,17 +12,13 @@ # License for the specific language governing permissions and limitations # under the License. # Korean (ko) -# Device Preferences '''Dry'''.ko=건조 '''Wet'''.ko=누수 '''dry'''.ko=건조 '''wet'''.ko=누수 '''battery'''.ko=배터리 -'''Temperature Offset'''.ko=온도 직접 설정 -'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다. -'''Degrees'''.ko=온도 -'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오 '''Give your device a name'''.ko=기기 이름 설정 +'''SmartThings Water Leak Sensor'''.ko=누수감지 센서 '''Water Leak Sensor'''.ko=누수감지 센서 '''${currentValue}% battery'''.ko=${currentValue}% 배터리 # Events descriptionText @@ -33,3 +29,102 @@ '''{{ device.displayName }} battery has too much power: (> 3.5) volts.'''.ko={{ device.displayName }} 배터리 전력이 너무 높습니다(3.5볼트 초과). '''{{ device.displayName }} battery was {{ value }}%'''.ko={{ device.displayName }}의 남은 배터리 {{ value }}% #============================================================================== + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy index 024400b0097..e57cd991447 100755 --- a/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy +++ b/devicetypes/smartthings/smartsense-moisture-sensor.src/smartsense-moisture-sensor.groovy @@ -26,13 +26,14 @@ metadata { capability "Health Check" capability "Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S", deviceJoinName: "Water Leak Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-L", deviceJoinName: "Iris Smart Water Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-G", deviceJoinName: "Centralite Water Sensor" - fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "water", deviceJoinName: "Water Leak Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S", deviceJoinName: "Water Leak Sensor", mnmn: "SmartThings", vid: "smartthings-water-leak-3315S-STSWTR" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315", deviceJoinName: "Water Leak Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor", mnmn: "SmartThings", vid: "smartthings-water-leak-3315S-STSWTR" + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-L", deviceJoinName: "Iris Water Leak Sensor" //Iris Smart Water Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-G", deviceJoinName: "Centralite Water Leak Sensor" //Centralite Water Sensor + fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor", mnmn: "SmartThings", vid: "smartthings-water-leak-3315S-STSWTR" + fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "water", deviceJoinName: "Water Leak Sensor", mnmn: "SmartThings", vid: "smartthings-water-leak-IM6001" + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Sercomm Corp.", model: "SZ-WTD03", deviceJoinName: "Sercomm Water Leak Sensor" //Sercomm Water Leak Detector } simulator { @@ -48,7 +49,7 @@ metadata { ]) } section { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } } @@ -138,7 +139,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F' map.translatable = true diff --git a/devicetypes/smartthings/smartsense-moisture.src/smartsense-moisture.groovy b/devicetypes/smartthings/smartsense-moisture.src/smartsense-moisture.groovy index b5ed43fda5a..eb6fb7c9af6 100644 --- a/devicetypes/smartthings/smartsense-moisture.src/smartsense-moisture.groovy +++ b/devicetypes/smartthings/smartsense-moisture.src/smartsense-moisture.groovy @@ -19,10 +19,10 @@ metadata { capability "Temperature Measurement" capability "Health Check" - fingerprint deviceId: "0x2001", inClusters: "0x30,0x9C,0x9D,0x85,0x80,0x72,0x31,0x84,0x86" - fingerprint deviceId: "0x2101", inClusters: "0x71,0x70,0x85,0x80,0x72,0x31,0x84,0x86" - fingerprint mfr:"0084", prod:"0063", model:"010C" - fingerprint mfr:"0084", prod:"0053", model:"0216", deviceJoinName: "FortrezZ Moisture Sensor" + fingerprint deviceId: "0x2001", inClusters: "0x30,0x9C,0x9D,0x85,0x80,0x72,0x31,0x84,0x86", deviceJoinName: "Water Leak Sensor" + fingerprint deviceId: "0x2101", inClusters: "0x71,0x70,0x85,0x80,0x72,0x31,0x84,0x86", deviceJoinName: "Water Leak Sensor" + fingerprint mfr:"0084", prod:"0063", model:"010C", deviceJoinName: "SmartThings Water Leak Sensor" + fingerprint mfr:"0084", prod:"0053", model:"0216", deviceJoinName: "FortrezZ Water Leak Sensor" //FortrezZ Moisture Sensor } simulator { diff --git a/devicetypes/smartthings/smartsense-motion-sensor.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-motion-sensor.src/i18n/messages.properties index efbd1bb2b81..8c25257baf0 100755 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/i18n/messages.properties +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/i18n/messages.properties @@ -11,15 +11,63 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + # Korean (ko) +'''SmartThings Motion Sensor'''.ko=동작감지 센서 +'''Motion Sensor'''.ko=동작감지 센서 + # Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset '''battery'''.ko=배터리 -'''Temperature Offset'''.ko=온도 직접 설정 -'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다. -'''Degrees'''.ko=온도 -'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오 '''Give your device a name'''.ko=기기 이름 설정 -'''Motion Sensor'''.ko=모션 센서 '''motion'''.ko= 동작 감지 '''no motion'''.ko=동작 없음 '''${currentValue}% battery'''.ko=${currentValue}% 배터리 @@ -33,7 +81,56 @@ #============================================================================== # Chinese +'''SmartThings Motion Sensor'''.zh-cn=人体传感器 '''Motion Sensor'''.zh-cn=人体传感器 +'''SmartThings Motion Sensor'''.zh-hk=SmartThings Motion Sensor '''Motion Sensor'''.zh-hk=Motion Sensor -'''Motion Sensor'''.ko=동작감지 센서 - \ No newline at end of file +# Device Preferences +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy index c2601a2f539..fc0b1948794 100644 --- a/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy +++ b/devicetypes/smartthings/smartsense-motion-sensor.src/smartsense-motion-sensor.groovy @@ -21,28 +21,28 @@ metadata { capability "Motion Sensor" capability "Configuration" capability "Battery" - capability "Temperature Measurement" + capability "Temperature Measurement" capability "Refresh" capability "Health Check" capability "Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305-S" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325-S", deviceJoinName: "Motion Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326-L", deviceJoinName: "Iris Motion Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3328-G", deviceJoinName: "Centralite Micro Motion Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "Motion Sensor-A", deviceJoinName: "SYLVANIA SMART+ Motion and Temperature Sensor" - fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor" - fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv5", deviceJoinName: "Motion Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0400,0500,0B05", outClusters: "0019", manufacturer: "Bosch", model: "RFPR-ZB", deviceJoinName: "Bosch Motion Sensor" - fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "Bosch", model: "RFDL-ZB-MS", deviceJoinName: "Bosch Motion Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "motion", deviceJoinName: "Motion Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Ecolink", model: "PIRZB1-ECO", deviceJoinName: "Ecolink Motion Detector" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305-S", deviceJoinName: "Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325-S", deviceJoinName: "Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3305", deviceJoinName: "Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3325", deviceJoinName: "Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326", deviceJoinName: "Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3326-L", deviceJoinName: "Iris Motion Sensor" //Iris Motion Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3328-G", deviceJoinName: "Centralite Motion Sensor" //Centralite Micro Motion Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "Motion Sensor-A", deviceJoinName: "SYLVANIA Motion Sensor" //SYLVANIA SMART+ Motion and Temperature Sensor + fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv4", deviceJoinName: "Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" + fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "motionv5", deviceJoinName: "Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion_Sensor" + fingerprint inClusters: "0000,0001,0003,0020,0400,0500,0B05", outClusters: "0019", manufacturer: "Bosch", model: "RFPR-ZB", deviceJoinName: "Bosch Motion Sensor" //Bosch Motion Sensor + fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "Bosch", model: "RFDL-ZB-MS", deviceJoinName: "Bosch Motion Sensor" //Bosch Motion Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500", outClusters: "0019", manufacturer: "Samjin", model: "motion", deviceJoinName: "Motion Sensor" // This is the only ST sensor that shouldn't use SmartThings-smartthings-SmartSense_Motion_Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Ecolink", model: "PIRZB1-ECO", deviceJoinName: "Ecolink Motion Sensor" //Ecolink Motion Detector //AduroSmart - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "ADUROLIGHT", model: "VMS_ADUROLIGHT", deviceJoinName: "ERIA Motion Sensor V2.0", mnmn: "SmartThings", vid: "generic-contact-3" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "AduroSmart Eria", model: "VMS_ADUROLIGHT", deviceJoinName: "ERIA Motion Sensor V2.1", mnmn: "SmartThings", vid: "generic-contact-3" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "ADUROLIGHT", model: "VMS_ADUROLIGHT", deviceJoinName: "ERIA Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2" //ERIA Motion Sensor V2.0 + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "AduroSmart Eria", model: "VMS_ADUROLIGHT", deviceJoinName: "ERIA Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2" //ERIA Motion Sensor V2.1 } simulator { @@ -59,7 +59,7 @@ metadata { ]) } section { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } } @@ -124,7 +124,7 @@ def parse(String description) { def battMap = descMaps.find { it.attrInt == 0x0021 } if (battMap) { - map = getBatteryPercentageResult(Integer.parseInt(battMap.value, 16)) + map = getBatteryPercentageResultSamjin(Integer.parseInt(battMap.value, 16)) } } else { def battMap = descMaps.find { it.attrInt == 0x0020 } @@ -133,7 +133,7 @@ def parse(String description) { map = getBatteryResult(Integer.parseInt(battMap.value, 16)) } } - } else if (descMap?.clusterInt == 0x0500 && descMap.attrInt == 0x0002) { + } else if (descMap?.clusterInt == 0x0500 && descMap.attrInt == 0x0002 && descMap.commandInt != 0x07) { def zs = new ZoneStatus(zigbee.convertToInt(descMap.value, 16)) map = translateZoneStatus(zs) } else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) { @@ -153,7 +153,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F' map.translatable = true @@ -244,18 +244,16 @@ private Map getBatteryResult(rawValue) { return result } -private Map getBatteryPercentageResult(rawValue) { - log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" - def result = [:] - - if (0 <= rawValue && rawValue <= 200) { - result.name = 'battery' - result.translatable = true - result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" - result.value = Math.round(rawValue / 2) - } +private Map getBatteryPercentageResultSamjin(rawValue) { + // This formula was provided by Samjin to effectively adjust the minimum voltage required for operation from 2.1V -> 2.4V + BigDecimal rawPercentage = rawValue - (200 - rawValue) / 2 + Integer percentage = Math.min(100, Math.max(Math.round(rawPercentage / 2), 0)) - return result + log.debug "Battery Percentage rawValue = ${rawValue} -> ${percentage}%" + return [name: 'battery', + translatable: true, + descriptionText: "{{ device.displayName }} battery was {{ value }}%", + value: percentage] } private Map getMotionResult(value) { @@ -336,4 +334,4 @@ private shouldUseOldBatteryReporting() { } return isFwVersionLess // If f/w version is less than 1.15.7 then do NOT smooth battery reports and use the old reporting -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy b/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy index 0b1a6d0c32c..944703c8bdf 100644 --- a/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy +++ b/devicetypes/smartthings/smartsense-motion.src/smartsense-motion.groovy @@ -12,15 +12,15 @@ * */ metadata { - definition (name: "SmartSense Motion", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, mnmn: "SmartThings", vid: "generic-motion-2") { + definition (name: "SmartSense Motion", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Motion") { capability "Signal Strength" capability "Motion Sensor" capability "Sensor" capability "Battery" capability "Health Check" - fingerprint profileId: "0104", deviceId: "013A", inClusters: "0000", outClusters: "0006" - fingerprint profileId: "FC01", deviceId: "013A" + fingerprint profileId: "0104", deviceId: "013A", inClusters: "0000", outClusters: "0006", deviceJoinName: "SmartThings Motion Sensor" + fingerprint profileId: "FC01", deviceId: "013A", deviceJoinName: "SmartThings Motion Sensor" } simulator { diff --git a/devicetypes/smartthings/smartsense-multi-sensor.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-multi-sensor.src/i18n/messages.properties index a6779c205bf..fa7397b5c2c 100755 --- a/devicetypes/smartthings/smartsense-multi-sensor.src/i18n/messages.properties +++ b/devicetypes/smartthings/smartsense-multi-sensor.src/i18n/messages.properties @@ -11,19 +11,15 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + # Korean (ko) -# Device Preferences -'''Yes'''.ko=예 -'''No'''.ko=아니요 +'''SmartThings Multipurpose Sensor'''.ko=문열림 센서 +'''Multipurpose Sensor'''.ko=문열림 센서 + +# Original Device Preferences '''battery'''.ko=배터리 -'''Temperature Offset'''.ko=온도 직접 설정 -'''This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter '-5'. If 3 degrees too cold, enter '+3'.'''.ko=기준 온도를 원하는대로 몇 도 올리거나 내려서 설정할 수 있습니다. -'''Degrees'''.ko=온도 -'''Adjust temperature by this many degrees'''.ko=몇 도씩 온도를 조절하십시오 -'''Do you want to use this sensor on a garage door?'''.ko=차고 문의 센서 사용 설정하기 -'''Tap to set'''.ko=눌러서 설정 '''Give your device a name'''.ko=기기 이름 설정 -'''Multipurpose Sensor'''.ko=문 및 창 센서 + # Events descriptionText '''{{ device.displayName }} was opened'''.ko={{ device.displayName }}에서 열림이 감지되었습니다. '''{{ device.displayName }} was closed'''.ko={{ device.displayName }}에서 닫힘이 감지되었습니다. @@ -44,3 +40,247 @@ # Chinese '''Multipurpose Sensor'''.zh-cn=门窗传感器 '''Multipurpose Sensor'''.zh-hk=Multipurpose Sensor +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +'''Use on garage door'''.en=Use on garage door +'''Use on garage door'''.en-gb=Use on garage door +'''Use on garage door'''.en-us=Use on garage door +'''Use on garage door'''.en-ca=Use on garage door +'''Use on garage door'''.sq=Përdore te dera e garazhit +'''Use on garage door'''.ar=الاستخدام على باب المرآب +'''Use on garage door'''.be=Выкарыст. на дзвярах гаража +'''Use on garage door'''.sr-ba=Koristi na garažnim vratima +'''Use on garage door'''.bg=Използване за гаражна врата +'''Use on garage door'''.ca=Utilitzar a porta del garatge +'''Use on garage door'''.zh-cn=在车库门上使用 +'''Use on garage door'''.zh-hk=用於車庫門 +'''Use on garage door'''.zh-tw=車庫門專用 +'''Use on garage door'''.hr=Upotrijebi za garažna vrata +'''Use on garage door'''.cs=Použít na garážových vratech +'''Use on garage door'''.da=Brug på garagedør +'''Use on garage door'''.nl=Gebruiken op garagedeur +'''Use on garage door'''.et=Garaažiuksega kasutamine +'''Use on garage door'''.fi=Käytä autotallin ovessa +'''Use on garage door'''.fr=Utilisation sur porte de garage +'''Use on garage door'''.fr-ca=Utilisation sur porte de garage +'''Use on garage door'''.de=Für Garagentor verwenden +'''Use on garage door'''.el=Χρήση στην πόρτα του γκαράζ +'''Use on garage door'''.iw=הצב על דלת החנייה +'''Use on garage door'''.hi-in=गेराज के दरवाजे पर उपयोग करें +'''Use on garage door'''.hu=Használat a garázskapun +'''Use on garage door'''.is=Nota á bílskúrshurð +'''Use on garage door'''.in=Gunakan di pintu garasi +'''Use on garage door'''.it=Usa su porta del garage +'''Use on garage door'''.ja=車庫用扉で使用 +'''Use on garage door'''.ko=차고문에 사용 +'''Use on garage door'''.lv=Izmantot garāžas durvīm +'''Use on garage door'''.lt=Naudoti ant garažo durų +'''Use on garage door'''.ms=Guna pada pintu garaj +'''Use on garage door'''.no=Bruk på garasjedør +'''Use on garage door'''.pl=Do bram garażowych +'''Use on garage door'''.pt=Utilizar na porta da garagem +'''Use on garage door'''.ro=Utilizare pentru ușa garajului +'''Use on garage door'''.ru=Установка на двери гаража +'''Use on garage door'''.sr=Koristi na vratima garaže +'''Use on garage door'''.sk=Použiť na garážových dverách +'''Use on garage door'''.sl=Uporaba za garažna vrata +'''Use on garage door'''.es=Usar en puerta de garaje +'''Use on garage door'''.sv=Använd på garagedörr +'''Use on garage door'''.th=ใช้กับประตูโรงรถ +'''Use on garage door'''.tr=Garaj kapısında kullan +'''Use on garage door'''.uk=Установлення на двері гаража +'''Use on garage door'''.vi=Sử dụng trên cửa ga-ra +'''No'''.en=No +'''No'''.en-gb=No +'''No'''.en-us=No +'''No'''.en-ca=No +'''No'''.en-ph=No +'''No'''.sq=Jo +'''No'''.ar=لا +'''No'''.be=Не +'''No'''.sr-ba=Ne +'''No'''.bg=Не +'''No'''.ca=No +'''No'''.zh-cn=不 +'''No'''.zh-hk=否 +'''No'''.zh-tw=否 +'''No'''.hr=Ne +'''No'''.cs=Ne +'''No'''.da=Nej +'''No'''.nl=Nee +'''No'''.et=Ei +'''No'''.fi=Ei +'''No'''.fr=Non +'''No'''.fr-ca=Non +'''No'''.de=Nein +'''No'''.el=Όχι +'''No'''.iw=לא +'''No'''.hi-in=नहीं +'''No'''.hu=Nem +'''No'''.is=Nei +'''No'''.in=Tidak +'''No'''.it=No +'''No'''.ja=いいえ +'''No'''.ko=아니요(문열림 센서) +'''No'''.lv=Nē +'''No'''.lt=Ne +'''No'''.ms=Tidak +'''No'''.no=Nei +'''No'''.pl=Nie +'''No'''.pt=Não +'''No'''.ro=Nu +'''No'''.ru=Нет +'''No'''.sr=Ne +'''No'''.sk=Nie +'''No'''.sl=Ne +'''No'''.es=No +'''No'''.sv=Nej +'''No'''.th=ไม่ +'''No'''.tr=Hayır +'''No'''.uk=Ні +'''No'''.vi=Không +'''Yes'''.en=Yes +'''Yes'''.en-gb=Yes +'''Yes'''.en-us=Yes +'''Yes'''.en-ca=Yes +'''Yes'''.en-ph=Yes +'''Yes'''.sq=Po +'''Yes'''.ar=نعم +'''Yes'''.be=Так +'''Yes'''.sr-ba=Da +'''Yes'''.bg=Да +'''Yes'''.ca=Sí +'''Yes'''.zh-cn=好的 +'''Yes'''.zh-hk=是 +'''Yes'''.zh-tw=是 +'''Yes'''.hr=Da +'''Yes'''.cs=Ano +'''Yes'''.da=Ja +'''Yes'''.nl=Ja +'''Yes'''.et=Jah +'''Yes'''.fi=Kyllä +'''Yes'''.fr=Oui +'''Yes'''.fr-ca=Oui +'''Yes'''.de=Ja +'''Yes'''.el=Ναι +'''Yes'''.iw=כן +'''Yes'''.hi-in=हाँ +'''Yes'''.hu=Igen +'''Yes'''.is=Já +'''Yes'''.in=Ya +'''Yes'''.it=Sì +'''Yes'''.ja=はい +'''Yes'''.ko=예(3축 가속도 센서) +'''Yes'''.lv=Jā +'''Yes'''.lt=Taip +'''Yes'''.ms=Ya +'''Yes'''.no=Ja +'''Yes'''.pl=Tak +'''Yes'''.pt=Sim +'''Yes'''.ro=Da +'''Yes'''.ru=Да +'''Yes'''.sr=Da +'''Yes'''.sk=Áno +'''Yes'''.sl=Da +'''Yes'''.es=Sí +'''Yes'''.sv=Ja +'''Yes'''.th=ใช่ +'''Yes'''.tr=Evet +'''Yes'''.uk=Так +'''Yes'''.vi=Có +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy index e71d5cf9c2d..0965e848582 100755 --- a/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy +++ b/devicetypes/smartthings/smartsense-multi-sensor.src/smartsense-multi-sensor.groovy @@ -17,7 +17,7 @@ import physicalgraph.zigbee.clusters.iaszone.ZoneStatus import physicalgraph.zigbee.zcl.DataType metadata { - definition(name: "SmartSense Multi Sensor", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, mnmn: "SmartThings", vid: "generic-contact-2") { + definition(name: "SmartSense Multi Sensor", namespace: "smartthings", author: "SmartThings", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: true, mnmn: "SmartThings", vid: "SmartThings-smartthings-SmartSense_Multi_Sensor") { capability "Three Axis" capability "Battery" @@ -29,13 +29,12 @@ metadata { capability "Temperature Measurement" capability "Health Check" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320", deviceJoinName: "Multipurpose Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321", deviceJoinName: "Multipurpose Sensor" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor" fingerprint inClusters: "0000,0001,0003,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "Samjin", model: "multi", deviceJoinName: "Multipurpose Sensor" - attribute "status", "string" } simulator { @@ -65,26 +64,20 @@ metadata { ]) } section { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } section { - input("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", description: "Tap to set", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false) + input("garageSensor", "enum", title: "Use on garage door", description: "", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false) } } tiles(scale: 2) { - multiAttributeTile(name: "status", type: "generic", width: 6, height: 4) { - tileAttribute("device.status", key: "PRIMARY_CONTROL") { - attributeState "open", label: 'Open', icon: "st.contact.contact.open", backgroundColor: "#e86d13" - attributeState "closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc" - attributeState "garage-open", label: 'Open', icon: "st.doors.garage.garage-open", backgroundColor: "#e86d13" - attributeState "garage-closed", label: 'Closed', icon: "st.doors.garage.garage-closed", backgroundColor: "#00a0dc" + multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4) { + tileAttribute("device.contact", key: "PRIMARY_CONTROL") { + attributeState("open", label: 'Open', icon: "st.contact.contact.open", backgroundColor: "#e86d13") + attributeState("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc") } } - standardTile("contact", "device.contact", width: 2, height: 2) { - state("open", label: 'Open', icon: "st.contact.contact.open", backgroundColor: "#e86d13") - state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc") - } standardTile("acceleration", "device.acceleration", width: 2, height: 2) { state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#00a0dc") state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#cccccc") @@ -110,8 +103,8 @@ metadata { } - main(["status", "acceleration", "temperature"]) - details(["status", "acceleration", "temperature", "battery", "refresh"]) + main(["contact", "acceleration", "temperature"]) + details(["contact", "acceleration", "temperature", "battery", "refresh"]) } } @@ -172,7 +165,7 @@ def parse(String description) { } else if (maps[0].name == "temperature") { def map = maps[0] if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F' map.translatable = true @@ -270,8 +263,7 @@ private List translateZoneStatus(ZoneStatus zs) { def value = zs.isAlarm1Set() ? 'open' : 'closed' log.debug "Contact: ${device.displayName} value = ${value}" def descriptionText = value == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed' - results << [name: 'contact', value: value, descriptionText: descriptionText, displayed: false, translatable: true] - results << [name: 'status', value: value, descriptionText: descriptionText, translatable: true] + results << [name: 'contact', value: value, descriptionText: descriptionText, translatable: true] } return results @@ -353,18 +345,14 @@ List garageEvent(zValue) { List results = [] def absValue = zValue.abs() def contactValue = null - def garageValue = null if (absValue > 900) { contactValue = 'closed' - garageValue = 'garage-closed' } else if (absValue < 100) { contactValue = 'open' - garageValue = 'garage-open' } if (contactValue != null) { def descriptionText = contactValue == 'open' ? '{{ device.displayName }} was opened' : '{{ device.displayName }} was closed' - results << [name: 'contact', value: contactValue, descriptionText: descriptionText, displayed: false, translatable: true] - results << [name: 'status', value: garageValue, descriptionText: descriptionText, translatable: true] + results << [name: 'contact', value: contactValue, descriptionText: descriptionText, translatable: true] } results } @@ -450,26 +438,6 @@ def configure() { return configCmds } -def updated() { - log.debug "updated called" - log.info "garage value : $garageSensor" - if (garageSensor == "Yes") { - def descriptionText = "Updating device to garage sensor" - if (device.latestValue("status") == "open") { - sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText, translatable: true) - } else if (device.latestValue("status") == "closed") { - sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText, translatable: true) - } - } else { - def descriptionText = "Updating device to open/close sensor" - if (device.latestValue("status") == "garage-open") { - sendEvent(name: 'status', value: 'open', descriptionText: descriptionText, translatable: true) - } else if (device.latestValue("status") == "garage-closed") { - sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText, translatable: true) - } - } -} - private hexToSignedInt(hexVal) { if (!hexVal) { return null diff --git a/devicetypes/smartthings/smartsense-multi.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-multi.src/i18n/messages.properties new file mode 100644 index 00000000000..1a64327c7c5 --- /dev/null +++ b/devicetypes/smartthings/smartsense-multi.src/i18n/messages.properties @@ -0,0 +1,112 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-multi.src/smartsense-multi.groovy b/devicetypes/smartthings/smartsense-multi.src/smartsense-multi.groovy index 673287ef2c9..efd0494c6c1 100644 --- a/devicetypes/smartthings/smartsense-multi.src/smartsense-multi.groovy +++ b/devicetypes/smartthings/smartsense-multi.src/smartsense-multi.groovy @@ -21,9 +21,7 @@ metadata { capability "Sensor" capability "Battery" - fingerprint profileId: "FC01", deviceId: "0139" - - attribute "status", "string" + fingerprint profileId: "FC01", deviceId: "0139", deviceJoinName: "Multipurpose Sensor" } simulator { @@ -45,7 +43,7 @@ metadata { } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } tiles(scale: 2) { @@ -121,17 +119,6 @@ private List parseSingleMessage(description) { displayed: displayed(description, isStateChange) ) - results << createEvent( - name: "status", - value: value, - unit: null, - linkText: linkText, - descriptionText: descriptionText, - handlerName: handlerName, - isStateChange: isStateChange, - displayed: displayed(description, isStateChange) - ) - results } @@ -297,19 +284,7 @@ private List getContactResult(part, description) { linkText: linkText, descriptionText: descriptionText, handlerName: handlerName, - isStateChange: isStateChange, - displayed:false - ) - - results << createEvent( - name: "status", - value: value, - unit: null, - linkText: linkText, - descriptionText: descriptionText, - handlerName: handlerName, - isStateChange: isStateChange, - displayed: displayed(description, isStateChange) + isStateChange: isStateChange ) results @@ -339,9 +314,7 @@ private Map getTempResult(part, description) { def temperatureScale = getTemperatureScale() def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale) if (tempOffset) { - def offset = tempOffset as int - def v = value as int - value = v + offset + value = new BigDecimal((value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } def linkText = getLinkText(device) def descriptionText = "$linkText was $value°$temperatureScale" diff --git a/devicetypes/smartthings/smartsense-open-closed-sensor.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-open-closed-sensor.src/i18n/messages.properties new file mode 100644 index 00000000000..1a64327c7c5 --- /dev/null +++ b/devicetypes/smartthings/smartsense-open-closed-sensor.src/i18n/messages.properties @@ -0,0 +1,112 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy b/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy index 8f35b4169c0..9f127bd884e 100644 --- a/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy +++ b/devicetypes/smartthings/smartsense-open-closed-sensor.src/smartsense-open-closed-sensor.groovy @@ -26,19 +26,21 @@ metadata { capability "Health Check" capability "Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3320-L", deviceJoinName: "Iris Contact Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3323-G", deviceJoinName: "Centralite Micro Door Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "Contact Sensor-A", deviceJoinName: "Sylvania SMART+ Contact and Temperature Smart Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Visonic", model: "MCT-340 E", deviceJoinName: "Visonic Door/Window Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Ecolink", model: "4655BC0-R", deviceJoinName: "Ecolink Door/Window Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05,FC01,FC02", outClusters: "0003,0019", manufacturer: "iMagic by GreatStar", model: "1116-S", deviceJoinName: "Iris Contact Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Bosch", model: "RFMS-ZBMS", deviceJoinName: "Bosch multi-sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Megaman", model: "MS601/z1", deviceJoinName: "INGENIUM ZB Magnetic ON/OFF Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S", deviceJoinName: "Open/Closed Sensor" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300", deviceJoinName: "Open/Closed Sensor" + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3320-L", deviceJoinName: "Iris Open/Closed Sensor" //Iris Contact Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3323-G", deviceJoinName: "Centralite Open/Closed Sensor" //Centralite Micro Door Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "Contact Sensor-A", deviceJoinName: "SYLVANIA Open/Closed Sensor" //Sylvania SMART+ Contact and Temperature Smart Sensor + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Visonic", model: "MCT-340 E", deviceJoinName: "Visonic Open/Closed Sensor" //Visonic Door/Window Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Ecolink", model: "4655BC0-R", deviceJoinName: "Ecolink Open/Closed Sensor", mnmn: "SmartThings", vid: "ecolink-door-sensor" //Ecolink Door/Window Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Ecolink", model: "DWZB1-ECO", deviceJoinName: "Ecolink Open/Closed Sensor", mnmn: "SmartThings", vid: "ecolink-door-sensor" //Ecolink Door/Window Sensor + fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05,FC01,FC02", outClusters: "0003,0019", manufacturer: "iMagic by GreatStar", model: "1116-S", deviceJoinName: "Iris Open/Closed Sensor" //Iris Contact Sensor + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Bosch", model: "RFMS-ZBMS", deviceJoinName: "Bosch Open/Closed Sensor" //Bosch multi-sensor + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Megaman", model: "MS601/z1", deviceJoinName: "INGENIUM Open/Closed Sensor" //INGENIUM ZB Magnetic ON/OFF Sensor //AduroSmart - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "CSW_ADUROLIGHT", deviceJoinName: "ERIA Contact Sensor V2.1", mnmn: "SmartThings", vid: "generic-contact-3" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "ADUROLIGHT", model: "CSW_ADUROLIGHT", deviceJoinName: "ERIA Contact Sensor V2.0", mnmn: "SmartThings", vid: "generic-contact-3" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "CSW_ADUROLIGHT", deviceJoinName: "ERIA Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-3" //ERIA Contact Sensor V2.1 + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "ADUROLIGHT", model: "CSW_ADUROLIGHT", deviceJoinName: "ERIA Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-3" //ERIA Contact Sensor V2.0 + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Sercomm Corp.", model: "SZ-DWS04", deviceJoinName: "Sercomm Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact" //Sercomm Door Window Sensor } simulator { @@ -46,7 +48,7 @@ metadata { } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } tiles(scale: 2) { @@ -126,7 +128,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F' map.translatable = true @@ -233,4 +235,4 @@ private Boolean isEcolink() { private Boolean isBoschRadionMultiSensor() { device.getDataValue("manufacturer") == "Bosch" && device.getDataValue("model") == "RFMS-ZBMS" -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/i18n/messages.properties new file mode 100755 index 00000000000..92e733232ce --- /dev/null +++ b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/i18n/messages.properties @@ -0,0 +1,210 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Multipurpose Sensor'''.zh-cn=海曼温湿度传感器 +'''HEIMAN Temperature & Humidity Sensor'''.zh-cn=海曼温湿度传感器 +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +'''Enter a percentage to adjust the humidity.'''.en=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-gb=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-us=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-ca=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.sq=Fut një përqindje për të përshtatur lagështinë. +'''Enter a percentage to adjust the humidity.'''.ar=أدخل نسبة مئوية لتعديل الرطوبة. +'''Enter a percentage to adjust the humidity.'''.be=Увядзіце працэнт, каб адрэгуляваць вільготнасць. +'''Enter a percentage to adjust the humidity.'''.sr-ba=Unesite procenat da prilagodite vlažnost. +'''Enter a percentage to adjust the humidity.'''.bg=Въведете процент, за да регулирате влажността. +'''Enter a percentage to adjust the humidity.'''.ca=Introdueix un percentatge per ajustar la humitat. +'''Enter a percentage to adjust the humidity.'''.zh-cn=请输入百分比来调整湿度。 +'''Enter a percentage to adjust the humidity.'''.zh-hk=輸入百分比以調整濕度。 +'''Enter a percentage to adjust the humidity.'''.zh-tw=請輸入百分比來調整濕度。 +'''Enter a percentage to adjust the humidity.'''.hr=Unesite postotak za promjenu vlažnosti. +'''Enter a percentage to adjust the humidity.'''.cs=Upravte vlhkost zadáním procenta. +'''Enter a percentage to adjust the humidity.'''.da=Angiv en procentsats for at justere fugtigheden. +'''Enter a percentage to adjust the humidity.'''.nl=Voer een percentage in om de vochtigheid aan te passen. +'''Enter a percentage to adjust the humidity.'''.et=Sisestage protsent, et muuta niiskust. +'''Enter a percentage to adjust the humidity.'''.fi=Anna prosentti kosteuden säätämistä varten. +'''Enter a percentage to adjust the humidity.'''.fr=Entrez un pourcentage pour ajuster l'humidité. +'''Enter a percentage to adjust the humidity.'''.de=Geben Sie einen Prozentsatz ein, um die Feuchtigkeit anzupassen. +'''Enter a percentage to adjust the humidity.'''.el=Εισαγάγετε ποσοστό για την προσαρμογή της υγρασίας. +'''Enter a percentage to adjust the humidity.'''.iw=כדי להתאים רמת לחות, הזן אחוז. +'''Enter a percentage to adjust the humidity.'''.hi-in=नमी समायोजित करने के लिए, प्रतिशत प्रविष्ट करें। +'''Enter a percentage to adjust the humidity.'''.hu=A páratartalom beállításához adjon meg egy százalékos értéket. +'''Enter a percentage to adjust the humidity.'''.is=Sláðu inn prósentu til að stilla rakastigið. +'''Enter a percentage to adjust the humidity.'''.in=Masukkan persentase untuk mengatur kelembapan. +'''Enter a percentage to adjust the humidity.'''.it=Inserite una percentuale per regolare l'umidità. +'''Enter a percentage to adjust the humidity.'''.ja=湿度を調整するパーセンテージを入力してください。 +'''Enter a percentage to adjust the humidity.'''.ko=원하는 습도율을 입력하고 실내 습도를 설정해 보세요. +'''Enter a percentage to adjust the humidity.'''.lv=Ievadiet procentuālo daudzumu, lai pielāgotu mitruma līmeni. +'''Enter a percentage to adjust the humidity.'''.lt=Įveskite procentus ir sureguliuokite drėgnumą. +'''Enter a percentage to adjust the humidity.'''.ms=Masukkan peratusan untuk melaraskan kelembapan. +'''Enter a percentage to adjust the humidity.'''.no=Angi en prosent for å justere fuktigheten. +'''Enter a percentage to adjust the humidity.'''.pl=Wprowadź procent, aby ustawić wilgotność. +'''Enter a percentage to adjust the humidity.'''.pt=Introduzir uma percentagem para ajustar a humidade. +'''Enter a percentage to adjust the humidity.'''.ro=Introduceți un procent pentru ajustarea umidității. +'''Enter a percentage to adjust the humidity.'''.ru=Введите процент для регулировки влажности. +'''Enter a percentage to adjust the humidity.'''.sr=Unesite procenat da biste prilagodili vlažnost. +'''Enter a percentage to adjust the humidity.'''.sk=Upravte vlhkosť zadaním percenta. +'''Enter a percentage to adjust the humidity.'''.sl=Vnesite odstotek, da prilagodite vlažnost. +'''Enter a percentage to adjust the humidity.'''.es=Introduce un porcentaje para ajustar la humedad. +'''Enter a percentage to adjust the humidity.'''.sv=Ange ett procenttal när du vill justera fuktigheten. +'''Enter a percentage to adjust the humidity.'''.th=ใส่เปอร์เซ็นต์เพื่อปรับความชื้น +'''Enter a percentage to adjust the humidity.'''.tr=Nemi ayarlamak için bir yüzde değeri girin. +'''Enter a percentage to adjust the humidity.'''.uk=Уведіть відсоток для регулювання вологості. +'''Enter a percentage to adjust the humidity.'''.vi=Nhập phần trăm để hiệu chỉnh độ ẩm. +'''Humidity offset'''.en=Humidity offset +'''Humidity offset'''.en-gb=Humidity offset +'''Humidity offset'''.en-us=Humidity offset +'''Humidity offset'''.en-ca=Humidity offset +'''Humidity offset'''.sq=Shmangia në lagështi +'''Humidity offset'''.ar=تعويض الرطوبة +'''Humidity offset'''.be=Карэкцыя вільготнасці +'''Humidity offset'''.sr-ba=Kompenzacija vlage +'''Humidity offset'''.bg=Компенсация на влажността +'''Humidity offset'''.ca=Compensació d'humitat +'''Humidity offset'''.zh-cn=湿度偏差 +'''Humidity offset'''.zh-hk=濕度偏差 +'''Humidity offset'''.zh-tw=濕度偏差 +'''Humidity offset'''.hr=Kompenzacija vlage +'''Humidity offset'''.cs=Posun vlhkosti +'''Humidity offset'''.da=Fugtighedsforskydning +'''Humidity offset'''.nl=Vochtigheidsverschil +'''Humidity offset'''.et=Niiskuse nihkeväärtus +'''Humidity offset'''.fi=Ilmankosteuden siirtymä +'''Humidity offset'''.fr=Compensation de l'humidité +'''Humidity offset'''.fr-ca=Compensation de l'humidité +'''Humidity offset'''.de=Luftfeuchtigkeitsabweichung +'''Humidity offset'''.el=Αντιστάθμιση υγρασίας +'''Humidity offset'''.iw=קיזוז לחות +'''Humidity offset'''.hi-in=नमी की भरपाई +'''Humidity offset'''.hu=Páratartalom-érték eltolása +'''Humidity offset'''.is=Vikmörk raka +'''Humidity offset'''.in=Offset kelembapan +'''Humidity offset'''.it=Differenza umidità +'''Humidity offset'''.ja=湿度オフセット +'''Humidity offset'''.ko=습도 오프셋 +'''Humidity offset'''.lv=Mitruma nobīde +'''Humidity offset'''.lt=Drėgnumo skirtumas +'''Humidity offset'''.ms=Ofset kelembapan +'''Humidity offset'''.no=Fuktighetsforskyvning +'''Humidity offset'''.pl=Różnica wilgotności +'''Humidity offset'''.pt=Diferença de humidade +'''Humidity offset'''.ro=Decalaj umiditate +'''Humidity offset'''.ru=Поправка влажности +'''Humidity offset'''.sr=Odstupanje vlažnosti +'''Humidity offset'''.sk=Posun vlhkosti +'''Humidity offset'''.sl=Odmik vlažnosti +'''Humidity offset'''.es=Compensación de humedad +'''Humidity offset'''.sv=Luftfuktighetsavvikelse +'''Humidity offset'''.th=การชดเชยความชื้น +'''Humidity offset'''.tr=Nem ofseti +'''Humidity offset'''.uk=Поправка вологості +'''Humidity offset'''.vi=Độ lệch độ ẩm +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy index 71c7cacc7bd..b600c95c1ef 100644 --- a/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/smartsense-temp-humidity-sensor.src/smartsense-temp-humidity-sensor.groovy @@ -25,11 +25,15 @@ metadata { capability "Health Check" capability "Sensor" - fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310-S", deviceJoinName: "SmartSense Temp & Humidity Sensor" - fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310-G", deviceJoinName: "Centralite Temp & Humidity Sensor" - fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310", deviceJoinName: "Temp & Humidity Sensor" - fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0402", manufacturer: "Heiman", model: "b467083cfc864f5e826459e5d8ea6079", deviceJoinName: "Orvibo Temperature & Humidity Sensor" - fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0402", manufacturer: "HEIMAN", model: "888a434f3cfc47f29ec4a3a03e9fc442", deviceJoinName: "Orvibo Temperature & Humidity Sensor" + + fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310-S", deviceJoinName: "Multipurpose Sensor" + fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310-G", deviceJoinName: "Centralite Multipurpose Sensor" //Centralite Temp & Humidity Sensor + fingerprint profileId: "0104", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003", manufacturer: "CentraLite", model: "3310", deviceJoinName: "Multipurpose Sensor" + fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0402", manufacturer: "Heiman", model: "b467083cfc864f5e826459e5d8ea6079", deviceJoinName: "Orvibo Multipurpose Sensor" //Orvibo Temperature & Humidity Sensor + fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0402", manufacturer: "HEIMAN", model: "888a434f3cfc47f29ec4a3a03e9fc442", deviceJoinName: "Orvibo Multipurpose Sensor" //Orvibo Temperature & Humidity Sensor + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0009, 0402", manufacturer: "HEIMAN", model: "HT-EM", deviceJoinName: "HEIMAN Multipurpose Sensor" //HEIMAN Temperature & Humidity Sensor + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0402, 0B05", manufacturer: "HEIMAN", model: "HT-EF-3.0", deviceJoinName: "HEIMAN Multipurpose Sensor" //HEIMAN Temperature & Humidity Sensor + } simulator { @@ -41,8 +45,8 @@ metadata { } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false - input "humidityOffset", "number", title: "Humidity Offset", description: "Adjust humidity by this percentage", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false + input "humidityOffset", "number", title: "Humidity offset", description: "Enter a percentage to adjust the humidity.", range: "*..*", displayDuringSetup: false } tiles(scale: 2) { @@ -83,7 +87,11 @@ def parse(String description) { if (!map) { Map descMap = zigbee.parseDescriptionAsMap(description) if (descMap.clusterInt == 0x0001 && descMap.commandInt != 0x07 && descMap?.value) { - map = getBatteryResult(Integer.parseInt(descMap.value, 16)) + if (descMap.attrInt == 0x0021) { + map = getBatteryPercentageResult(Integer.parseInt(descMap.value,16)) + } else { + map = getBatteryResult(Integer.parseInt(descMap.value, 16)) + } } else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) { if (descMap.data[0] == "00") { log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap" @@ -94,7 +102,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F' map.translatable = true @@ -108,6 +116,21 @@ def parse(String description) { return map ? createEvent(map) : [:] } + +def getBatteryPercentageResult(rawValue) { + log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" + def result = [:] + + if (0 <= rawValue && rawValue <= 200) { + result.name = 'battery' + result.translatable = true + result.value = Math.round(rawValue / 2) + result.descriptionText = "${device.displayName} battery was ${result.value}%" + } + + return result +} + private Map getBatteryResult(rawValue) { log.debug 'Battery' def linkText = getLinkText(device) diff --git a/devicetypes/smartthings/smartsense-virtual-open-closed.src/i18n/messages.properties b/devicetypes/smartthings/smartsense-virtual-open-closed.src/i18n/messages.properties new file mode 100644 index 00000000000..1a64327c7c5 --- /dev/null +++ b/devicetypes/smartthings/smartsense-virtual-open-closed.src/i18n/messages.properties @@ -0,0 +1,112 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/smartsense-virtual-open-closed.src/smartsense-virtual-open-closed.groovy b/devicetypes/smartthings/smartsense-virtual-open-closed.src/smartsense-virtual-open-closed.groovy index a50270d37e4..47352273166 100644 --- a/devicetypes/smartthings/smartsense-virtual-open-closed.src/smartsense-virtual-open-closed.groovy +++ b/devicetypes/smartthings/smartsense-virtual-open-closed.src/smartsense-virtual-open-closed.groovy @@ -45,7 +45,7 @@ metadata { } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } tiles { @@ -278,9 +278,7 @@ private getTempResult(part, description) { def temperatureScale = getTemperatureScale() def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale) if (tempOffset) { - def offset = tempOffset as int - def v = value as int - value = v + offset + value = new BigDecimal((value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } def linkText = getLinkText(device) def descriptionText = "$linkText was $value°$temperatureScale" diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.apparentTemperature.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.apparentTemperature.json new file mode 100644 index 00000000000..e09e7d0a68b --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.apparentTemperature.json @@ -0,0 +1,32 @@ +{ + "name": "Apparent Temperature", + "attributes": { + "feelsLike": { + "schema": { + "type": "object", + "properties": { + "value": { + "title": "TemperatureValue", + "type": "number", + "minimum": -460, + "maximum": 10000 + }, + "unit": { + "type": "string", + "enum": [ + "F", + "C" + ] + } + }, + "additionalProperties": false, + "required": [ + "value", + "unit" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.astronomicalData.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.astronomicalData.json new file mode 100644 index 00000000000..580712fe207 --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.astronomicalData.json @@ -0,0 +1,91 @@ +{ + "name": "Astronomical Data", + "attributes": { + "localSunrise": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "localSunset": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "sunriseDate": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "sunsetDate": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "city": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "timeZoneOffset": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.precipitation.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.precipitation.json new file mode 100644 index 00000000000..af66d52e047 --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.precipitation.json @@ -0,0 +1,31 @@ +{ + "name": "Precipitation", + "attributes": { + "percentPrecip": { + "schema": { + "type": "object", + "properties": { + "value": { + "title": "IntegerPercent", + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "unit": { + "type": "string", + "enum": [ + "%" + ], + "default": "%" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.smartWeather.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.smartWeather.json new file mode 100644 index 00000000000..fac90437e04 --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.smartWeather.json @@ -0,0 +1,21 @@ +{ + "name": "Smart Weather", + "attributes": { + "lastUpdate": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.ultravioletDescription.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.ultravioletDescription.json new file mode 100644 index 00000000000..5dc33becb1f --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.ultravioletDescription.json @@ -0,0 +1,21 @@ +{ + "name": "Ultraviolet Description", + "attributes": { + "uvDescription": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherAlert.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherAlert.json new file mode 100644 index 00000000000..743bc466e4d --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherAlert.json @@ -0,0 +1,35 @@ +{ + "name": "Weather Alert", + "attributes": { + "alert": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "alertKeys": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherForecast.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherForecast.json new file mode 100644 index 00000000000..e8677bb7516 --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherForecast.json @@ -0,0 +1,63 @@ +{ + "name": "Weather Forecast", + "attributes": { + "forecastIcon": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "forecastToday": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "forecastTonight": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "forecastTomorrow": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherSummary.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherSummary.json new file mode 100644 index 00000000000..a680a801a28 --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.weatherSummary.json @@ -0,0 +1,35 @@ +{ + "name": "Weather Summary", + "attributes": { + "weather": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + }, + "weatherIcon": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windDirection.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windDirection.json new file mode 100644 index 00000000000..d10625d4cd3 --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windDirection.json @@ -0,0 +1,21 @@ +{ + "name": "Wind Direction", + "attributes": { + "windVector": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "value" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windSpeed.json b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windSpeed.json new file mode 100644 index 00000000000..9994d651c48 --- /dev/null +++ b/devicetypes/smartthings/smartweather-station-tile.src/capability.stsmartweather.windSpeed.json @@ -0,0 +1,27 @@ +{ + "name": "Wind Speed", + "attributes": { + "wind": { + "schema": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "unit": { + "type": "string", + "enum": ["KPH", "MPH"], + "default": "KPH" + } + }, + "additionalProperties": false, + "required": [ + "value", + "unit" + ] + } + } + }, + "commands": { + } +} diff --git a/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy b/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy index 04849e96b6c..77c3dfbb558 100644 --- a/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy +++ b/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy @@ -22,9 +22,21 @@ metadata { capability "Temperature Measurement" capability "Relative Humidity Measurement" capability "Ultraviolet Index" + //capability "Wind Speed" // Not in production yet + capability "stsmartweather.windSpeed" // "Wind Speed" only supports m/s unit, however we want to create both events + capability "stsmartweather.windDirection" + capability "stsmartweather.apparentTemperature" + capability "stsmartweather.astronomicalData" + capability "stsmartweather.precipitation" + capability "stsmartweather.ultravioletDescription" + capability "stsmartweather.weatherAlert" + capability "stsmartweather.weatherForecast" + capability "stsmartweather.weatherSummary" capability "Sensor" capability "Refresh" + // While we have created a custom capability for these attributes, + // they will remain to support any custom DataManagement based SmartApps using them. attribute "localSunrise", "string" attribute "localSunset", "string" attribute "city", "string" @@ -150,7 +162,7 @@ metadata { state "default", label:'${currentValue}' } - standardTile("refresh", "device.weather", decoration: "flat", height: 1, width: 2) { + standardTile("refresh", "device.refresh", decoration: "flat", height: 1, width: 2) { state "default", label: "", action: "refresh", icon:"st.secondary.refresh" } @@ -211,7 +223,7 @@ def uninstalled() { // handle commands def poll() { - log.info "WUSTATION: Executing 'poll', location: ${location.name}" + log.debug "WUSTATION: Executing 'poll', location: ${location.name}" if (stationId) { pollUsingPwsId(stationId.toUpperCase()) } else { @@ -228,7 +240,7 @@ def pollUsingZipCode(String zipCode) { // Last update time stamp def timeZone = location.timeZone ?: timeZone(timeOfDay) def timeStamp = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone) - sendEvent(name: "lastUpdate", value: timeStamp) + send(name: "lastUpdate", value: timeStamp) // Current conditions def tempUnits = getTemperatureScale() @@ -242,8 +254,8 @@ def pollUsingZipCode(String zipCode) { send(name: "humidity", value: obs.relativeHumidity, unit: "%") send(name: "weather", value: obs.wxPhraseShort) - send(name: "weatherIcon", value: obs.iconCode as String, displayed: false) - send(name: "wind", value: obs.windSpeed as String, unit: windUnits) // as String because of bug in determining state change of 0 numbers + send(name: "weatherIcon", value: obs.iconCode, displayed: false) + send(name: "wind", value: obs.windSpeed, unit: windUnits) send(name: "windVector", value: "${obs.windDirectionCardinal} ${obs.windSpeed} ${windUnits}") log.trace "Getting location info" def loc = getTwcLocation(zipCode).location @@ -258,7 +270,7 @@ def pollUsingZipCode(String zipCode) { def dtf = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") def sunriseDate = dtf.parse(obs.sunriseTimeLocal) - log.info "'${obs.sunriseTimeLocal}'" + log.debug "'${obs.sunriseTimeLocal}'" def sunsetDate = dtf.parse(obs.sunsetTimeLocal) @@ -276,13 +288,14 @@ def pollUsingZipCode(String zipCode) { def f = getTwcForecast(zipCode) if (f) { def icon = f.daypart[0].iconCode[0] ?: f.daypart[0].iconCode[1] - def value = f.daypart[0].precipChance[0] ?: f.daypart[0].precipChance[1] + def precip = f.daypart[0].precipChance[0] ?: f.daypart[0].precipChance[1] def narrative = f.daypart[0].narrative - send(name: "percentPrecip", value: value as String, unit: "%") - send(name: "forecastIcon", value: icon as String, displayed: false) - send(name: "forecastToday", value: narrative[0]) - send(name: "forecastTonight", value: narrative[1]) - send(name: "forecastTomorrow", value: narrative[2]) + + send(name: "percentPrecip", value: precip, unit: "%") + send(name: "forecastIcon", value: icon, displayed: false) + send(name: "forecastToday", value: narrative[0] ?: "-") + send(name: "forecastTonight", value: narrative[1] ?: "-") + send(name: "forecastTomorrow", value: narrative[2] ?: "-") } else { log.warn "Forecast not found" @@ -331,8 +344,8 @@ def pollUsingPwsId(String stationId) { send(name: "humidity", value: obs.humidity, unit: "%") send(name: "weather", value: "n/a") - send(name: "weatherIcon", value: null as String, displayed: false) - send(name: "wind", value: convertWindSpeed(obs[dataScale].windSpeed, dataScale, tempUnits) as String, unit: windUnits) // as String because of bug in determining state change of 0 numbers + send(name: "weatherIcon", value: null, displayed: false) + send(name: "wind", value: convertWindSpeed(obs[dataScale].windSpeed, dataScale, tempUnits), unit: windUnits) send(name: "windVector", value: "${obs.winddir}° ${convertWindSpeed(obs[dataScale].windSpeed, dataScale, tempUnits)} ${windUnits}") def cityValue = obs.neighborhood if (cityValue != device.currentValue("city")) { @@ -418,9 +431,41 @@ private localDate(timeZone) { df.format(new Date()) } -private send(map) { - log.debug "WUSTATION: event: $map" +// Create the new custom capability event if needed, +// but also send a legacy custom event for any DM-backed SmartApps using them. +private send(Map map) { + def eventConversion = [ + "localSunrise": "stsmartweather.astronomicalData.localSunrise", + "localSunset": "stsmartweather.astronomicalData.localSunset", + "city": "stsmartweather.astronomicalData.city", + "timeZoneOffset": "stsmartweather.astronomicalData.timeZoneOffset", + "weather": "stsmartweather.weatherSummary.weather", + "wind": "stsmartweather.windSpeed.wind", + "windVector": "stsmartweather.windDirection.windVector", + "weatherIcon": "stsmartweather.weatherSummary.weatherIcon", + "forecastIcon": "stsmartweather.weatherForecast.forecastIcon", + "feelsLike": "stsmartweather.apparentTemperature.feelsLike", + "percentPrecip": "stsmartweather.precipitation.percentPrecip", + "alert": "stsmartweather.weatherAlert.alert", + "alertKeys": "stsmartweather.weatherAlert.alertKeys", + "sunriseDate": "stsmartweather.astronomicalData.sunriseDate", + "sunsetDate": "stsmartweather.astronomicalData.sunsetDate", + "lastUpdate": "stsmartweather.smartWeather.lastUpdate", + "uvDescription": "stsmartweather.ultravioletDescription.uvDescription", + "forecastToday": "stsmartweather.weatherForecast.forecastToday", + "forecastTonight": "stsmartweather.weatherForecast.forecastTonight", + "forecastTomorrow": "stsmartweather.weatherForecast.forecastTomorrow" + ] + + //log.trace "WUSTATION: event: $map" sendEvent(map) + if (map.name && eventConversion.containsKey(map.name)) { + def newMap = map.clone() + newMap.name = eventConversion[map.name] + + //log.trace "WUSTATION: NEW event: $newMap" + sendEvent(newMap) + } } private estimateLux(obs, sunriseDate, sunsetDate) { diff --git a/devicetypes/smartthings/springs-window-fashions-remote.src/springs-window-fashions-remote.groovy b/devicetypes/smartthings/springs-window-fashions-remote.src/springs-window-fashions-remote.groovy index 1694534186a..c1df8f4e752 100644 --- a/devicetypes/smartthings/springs-window-fashions-remote.src/springs-window-fashions-remote.groovy +++ b/devicetypes/smartthings/springs-window-fashions-remote.src/springs-window-fashions-remote.groovy @@ -16,8 +16,8 @@ metadata { capability "Battery" - fingerprint mfr:"026E", prod:"5643", model:"5A31", deviceJoinName: "2 Button Window Remote" - fingerprint mfr:"026E", prod:"4252", model:"5A31", deviceJoinName: "3 Button Window Remote" + fingerprint mfr:"026E", prod:"5643", model:"5A31", deviceJoinName: "Springs Remote Control" //2 Button Window Remote + fingerprint mfr:"026E", prod:"4252", model:"5A31", deviceJoinName: "Springs Remote Control" //3 Button Window Remote } simulator { @@ -107,7 +107,7 @@ private command(physicalgraph.zwave.Command cmd) { private getDeviceIsSecure() { if (zwaveInfo && zwaveInfo.zw) { - return zwaveInfo.zw.endsWith("s") + return zwaveInfo.zw.contains("s") } else { return state.sec ? true : false } diff --git a/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy b/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy index 45687fb4ef0..7af556576ba 100644 --- a/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy +++ b/devicetypes/smartthings/springs-window-fashions-shade.src/springs-window-fashions-shade.groovy @@ -32,8 +32,8 @@ metadata { // // fingerprint type: "0x1107", cc: "0x5E,0x26", deviceJoinName: "Window Shade" // fingerprint type: "0x9A00", cc: "0x5E,0x26", deviceJoinName: "Window Shade" - fingerprint mfr:"026E", prod:"4353", model:"5A31", deviceJoinName: "Window Shade" - fingerprint mfr:"026E", prod:"5253", model:"5A31", deviceJoinName: "Roller Shade" + fingerprint mfr:"026E", prod:"4353", model:"5A31", deviceJoinName: "Springs Window Treatment" //Window Shade + fingerprint mfr:"026E", prod:"5253", model:"5A31", deviceJoinName: "Springs Window Treatment" //Roller Shade } simulator { @@ -164,6 +164,7 @@ private handleLevelReport(physicalgraph.zwave.Command cmd) { shadeValue = "partially open" descriptionText = "${device.displayName} shade is ${level}% open" } + checkLevelReport(level) def levelEvent = createEvent(name: "level", value: level, unit: "%", displayed: false) def stateEvent = createEvent(name: "windowShade", value: shadeValue, descriptionText: descriptionText, isStateChange: levelEvent.isStateChange) @@ -181,15 +182,6 @@ def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelS response(zwave.switchMultilevelV1.switchMultilevelGet().format()) ] } -def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { - def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) - updateDataValue("MSR", msr) - if (cmd.manufacturerName) { - updateDataValue("manufacturer", cmd.manufacturerName) - } - createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false]) -} - def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF || cmd.batteryLevel == 0) { @@ -200,7 +192,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { map.value = cmd.batteryLevel } state.lastbatt = now() - if (map.value <= 1 && device.latestValue("battery") - map.value > 20) { + if (map.value <= 1 && device.latestValue("battery") != null && device.latestValue("battery") - map.value > 20) { // Springs shades sometimes erroneously report a low battery when rapidly actuated manually. They'll still // refuse to actuate after one of these reports, but this will limit the bad data that gets surfaced log.warn "Erroneous battery report dropped from ${device.latestValue("battery")} to $map.value. Not reporting" @@ -222,6 +214,7 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { def open() { log.debug "open()" def level = switchDirection ? 0 : 99 + levelChangeFollowUp(level) zwave.basicV1.basicSet(value: level).format() // zwave.basicV1.basicSet(value: 0xFF).format() } @@ -229,6 +222,7 @@ def open() { def close() { log.debug "close()" def level = switchDirection ? 99 : 0 + levelChangeFollowUp(level) zwave.basicV1.basicSet(value: level).format() //zwave.basicV1.basicSet(value: 0).format() } @@ -239,6 +233,7 @@ def setLevel(value, duration = null) { level = switchDirection ? 99-level : level if (level < 0) level = 0 if (level > 99) level = 99 + levelChangeFollowUp(level) zwave.basicV1.basicSet(value: level).format() } @@ -266,4 +261,29 @@ def refresh() { zwave.switchMultilevelV1.switchMultilevelGet().format(), zwave.batteryV1.batteryGet().format() ], 1500) +} + +def levelChangeFollowUp(expectedLevel) { + state.expectedValue = expectedLevel + state.levelChecks = 0 + runIn(5, "checkLevel", [overwrite: true]) +} + +def checkLevelReport(value) { + if (state.expectedValue != null) { + if ((state.expectedValue == 99 && value >= 99) || + (value >= state.expectedValue - 2 && value <= state.expectedValue + 2)) { + unschedule("checkLevel") + } + } +} + +def checkLevel() { + if (state.levelChecks != null && state.levelChecks < 5) { + state.levelChecks = state.levelChecks + 1 + runIn(5, "checkLevel", [overwrite: true]) + sendHubCommand(zwave.switchMultilevelV1.switchMultilevelGet()) + } else { + unschedule("checkLevel") + } } \ No newline at end of file diff --git a/devicetypes/smartthings/temperature-sensor.src/temperature-sensor.groovy b/devicetypes/smartthings/temperature-sensor.src/temperature-sensor.groovy index 16ed5824bd5..1f7841d4cad 100644 --- a/devicetypes/smartthings/temperature-sensor.src/temperature-sensor.groovy +++ b/devicetypes/smartthings/temperature-sensor.src/temperature-sensor.groovy @@ -17,7 +17,7 @@ metadata { capability "Relative Humidity Measurement" capability "Sensor" - fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0009,0402,0405" + fingerprint profileId: "0104", deviceId: "0302", inClusters: "0000,0001,0003,0009,0402,0405", deviceJoinName: "Temperature Sensor" } // simulator metadata diff --git a/devicetypes/smartthings/testing/simulated-device-preferences.src/simulated-device-preferences.groovy b/devicetypes/smartthings/testing/simulated-device-preferences.src/simulated-device-preferences.groovy index 6851e13bf9d..a4501c899e3 100644 --- a/devicetypes/smartthings/testing/simulated-device-preferences.src/simulated-device-preferences.groovy +++ b/devicetypes/smartthings/testing/simulated-device-preferences.src/simulated-device-preferences.groovy @@ -22,31 +22,49 @@ metadata { preferences { section { - input(title: "Section 1 Title", - description: "Section 1 Description", + input(title: "======= Enum Types Title =======", + description: "Enum Types Description", displayDuringSetup: false, type: "paragraph", element: "paragraph") - input("textInput", "text", - title: "Text Title", - description: "Text Description", - defaultValue: "default value", - required: false) input("enumInput", "enum", title: "Enum Title (key/value options)", description: "Enum Description (key/value options)", - options: ["Option1Key":"Option 1 Value", "Option2Key":"Option 2 Value", "Option3Key":"Option 3 Value", "Option4Key":"Option 4 Value"], - defaultValue: "Option1Key", + options: ["Enum1 - Option A Key": "Enum1 - Option A Value", + "Enum1 - Option B Key": "Enum1 - Option B Value", + "Enum1 - Option C Key": "Enum1 - Option C Value", + "Enum1 - Option D Key": "Enum1 - Option D Value"], + defaultValue: "Enum1 - Option A Key", required: false) input("enumInput2", "enum", - title: "Enum Title 2 (value options)", - description: "Enum Description 2 (value options)", - options: ["Option 1 Value", "Option 2 Value", "Option 3 Value", "Option 4 Value"], - defaultValue: "Option 1 Value", + title: "Enum Title 2 (List of options)", + description: "Enum Description 2 (List of options)", + options: ["Enum2 - Option A Value", + "Enum2 - Option B Value", + "Enum2 - Option C Value", + "Enum2 - Option D Value"], + defaultValue: "Enum2 - Option A Value", required: false) input("enumInput3", "enum", - title: "Enum Title 3 (no options)", description: "Enum Description 3 (no options)", + title: "Enum Title 3 (Lists of Maps options)", + description: "Enum Description 3 (Lists of Maps options)", + options: [ + ["Enum3 - Option A Key": "Enum3 - Option A Value"], + ["Enum3 - Option B Key": "Enum3 - Option B Value"], + ["Enum3 - Option C Key": "Enum3 - Option C Value"], + ["Enum3 - Option D Key": "Enum3 - Option D Value"]], + defaultValue: "Enum3 - Option A Key", + required: false) + input("enumInput4", "enum", + title: "Enum Title 4 (no options)", description: "Enum Description 4 (no options)", required: false) + } + section { + input(title: "======= Boolean Types Title =======", + description: "Boolean Types Description", + displayDuringSetup: false, + type: "paragraph", + element: "paragraph") input("booleanInput", "boolean", title: "Boolean Title", description: "Boolean Description", @@ -59,8 +77,8 @@ metadata { required: false) } section { - input(title: "Section 2 Title", - description: "Section 2 Description", + input(title: "======= Numerical Types Title =======", + description: "Numerical Types Description", displayDuringSetup: false, type: "paragraph", element: "paragraph") @@ -92,6 +110,19 @@ metadata { description: "Decimal Description", defaultValue: "5.0", required: false) + + } + section { + input(title: "======= Other Types Title =======", + description: "Other Types Description", + displayDuringSetup: false, + type: "paragraph", + element: "paragraph") + input("textInput", "text", + title: "Text Title", + description: "Text Description", + defaultValue: "default value", + required: false) input("passInput", "password", title: "Password Title", description: "Password Description", @@ -134,6 +165,7 @@ def updated() { enumInput: enumInput, enumInput2: enumInput2, enumInput3: enumInput3, + enumInput4: enumInput4, numInput: numInput, numInput2: numInput2, numInput3: numInput3, @@ -141,8 +173,11 @@ def updated() { passInput: passInput, textInput: textInput ] - log.debug "Current preferences: ${state.preferences}" - log.debug "New preferences: ${newPreferences}" + newPreferences.each { k, v -> + if (state.preferences[k] != v) { + log.debug "Changing preference '$k' from '${state.preferences[k]}' to '$v'" + } + } state.preferences = newPreferences } diff --git a/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy b/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy index 5d12735b89d..973e59e3901 100644 --- a/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy +++ b/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy @@ -505,7 +505,7 @@ private Map buildColorHSMap(hue, saturation) { } catch (NumberFormatException nfe) { log.warn "Couldn't transform one of hue ($hue) or saturation ($saturation) to integers: $nfe" } - return colorHSmap + return colorHSMap } /** diff --git a/devicetypes/smartthings/tyco-door-window-sensor.src/i18n/messages.properties b/devicetypes/smartthings/tyco-door-window-sensor.src/i18n/messages.properties new file mode 100644 index 00000000000..1a64327c7c5 --- /dev/null +++ b/devicetypes/smartthings/tyco-door-window-sensor.src/i18n/messages.properties @@ -0,0 +1,112 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy b/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy index 8c3deab8fc9..8e5d5c5410b 100644 --- a/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy +++ b/devicetypes/smartthings/tyco-door-window-sensor.src/tyco-door-window-sensor.groovy @@ -25,7 +25,7 @@ metadata { capability "Health Check" capability "Sensor" - fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Visonic", model: "MCT-340 SMA" + fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Visonic", model: "MCT-340 SMA", deviceJoinName: "Tyco Open/Closed Sensor" } simulator { @@ -33,7 +33,7 @@ metadata { } preferences { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } tiles(scale: 2) { @@ -208,9 +208,7 @@ private Map getTemperatureResult(value) { log.debug 'TEMP' def linkText = getLinkText(device) if (tempOffset) { - def offset = tempOffset as int - def v = value as int - value = v + offset + value = new BigDecimal((value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } def descriptionText = "${linkText} was ${value}°${temperatureScale}" return [ diff --git a/devicetypes/smartthings/zigbee-accessory-dimmer.src/zigbee-accessory-dimmer.groovy b/devicetypes/smartthings/zigbee-accessory-dimmer.src/zigbee-accessory-dimmer.groovy index 8f717dc64f8..9ceb3370e1d 100644 --- a/devicetypes/smartthings/zigbee-accessory-dimmer.src/zigbee-accessory-dimmer.groovy +++ b/devicetypes/smartthings/zigbee-accessory-dimmer.src/zigbee-accessory-dimmer.groovy @@ -23,8 +23,8 @@ metadata { capability "Configuration" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000,1000,0003", outClusters: "0003,0004,0005,0006,0008,1000,0019", manufacturer: "Aurora", model: "Remote50AU", deviceJoinName: "Aurora Wireless Wall Remote" - fingerprint profileId: "0104", inClusters: "0000,1000,0003", outClusters: "0003,0004,0005,0006,0008,1000,0019", manufacturer: "LDS", model: "ZBT-DIMController-D0800", deviceJoinName: "Müller Licht Tint Mobile Switch" + fingerprint profileId: "0104", inClusters: "0000,1000,0003", outClusters: "0003,0004,0005,0006,0008,1000,0019", manufacturer: "Aurora", model: "Remote50AU", deviceJoinName: "Aurora Dimmer Switch" //Aurora Wireless Wall Remote + fingerprint profileId: "0104", inClusters: "0000,1000,0003", outClusters: "0003,0004,0005,0006,0008,1000,0019", manufacturer: "LDS", model: "ZBT-DIMController-D0800", deviceJoinName: "Tint Dimmer Switch" //Müller Licht Tint Mobile Switch } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zigbee-battery-accessory-dimmer.src/zigbee-battery-accessory-dimmer.groovy b/devicetypes/smartthings/zigbee-battery-accessory-dimmer.src/zigbee-battery-accessory-dimmer.groovy index 3380f7e6b11..0cb4774574e 100644 --- a/devicetypes/smartthings/zigbee-battery-accessory-dimmer.src/zigbee-battery-accessory-dimmer.groovy +++ b/devicetypes/smartthings/zigbee-battery-accessory-dimmer.src/zigbee-battery-accessory-dimmer.groovy @@ -23,9 +23,9 @@ metadata { capability "Switch Level" // Sengled Switch is moved to the CST because of issues with battery reports so our way to resolve this is to hide the battery in OneApp by using metadata without it. - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,FC11", outClusters: "0003,0004,0006,0008,FC10", manufacturer: "sengled", model: "E1E-G7F", deviceJoinName: "Sengled Smart Switch", mnmn:"SmartThings", vid: "generic-dimmer" - fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI wireless dimmer", deviceJoinName: "IKEA TRÅDFRI Wireless dimmer" // 01 [0104 or C05E] 0810 02 06 0000 0001 0003 0009 0B05 1000 06 0003 0004 0006 0008 0019 1000 - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0B05", outClusters: "0003,0006,0008,0019", manufacturer: "Centralite Systems", model: "3131-G", deviceJoinName: "Centralite Smart Switch" + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,FC11", outClusters: "0003,0004,0006,0008,FC10", manufacturer: "sengled", model: "E1E-G7F", deviceJoinName: "Sengled Dimmer Switch", mnmn:"SmartThings", vid: "generic-dimmer" //Sengled Smart Switch + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI wireless dimmer", deviceJoinName: "IKEA Dimmer Switch" // 01 [0104 or C05E] 0810 02 06 0000 0001 0003 0009 0B05 1000 06 0003 0004 0006 0008 0019 1000 //IKEA TRÅDFRI Wireless dimmer + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0B05", outClusters: "0003,0006,0008,0019", manufacturer: "Centralite Systems", model: "3131-G", deviceJoinName: "Centralite Dimmer Switch" //Centralite Smart Switch } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy b/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy old mode 100644 new mode 100755 index c876bad08ac..aa74ac7193a --- a/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy +++ b/devicetypes/smartthings/zigbee-button.src/zigbee-button.groovy @@ -28,10 +28,10 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "OSRAM", model: "LIGHTIFY Dimming Switch", deviceJoinName: "OSRAM LIGHTIFY Dimming Switch" - fingerprint inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "CentraLite", model: "3130", deviceJoinName: "Centralite Zigbee Smart Switch" - fingerprint inClusters: "0000, 0001, 0003, 0020, 0500", outClusters: "0003,0019", manufacturer: "CentraLite", model: "3455-L", deviceJoinName: "Iris Care Pendant" - fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0402, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model: "3460-L", deviceJoinName: "Iris Smart Button" + fingerprint inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "OSRAM", model: "LIGHTIFY Dimming Switch", deviceJoinName: "OSRAM Button" //OSRAM LIGHTIFY Dimming Switch + fingerprint inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "CentraLite", model: "3130", deviceJoinName: "Centralite Button" //Centralite Zigbee Smart Switch + fingerprint inClusters: "0000, 0001, 0003, 0020, 0500", outClusters: "0003,0019", manufacturer: "CentraLite", model: "3455-L", deviceJoinName: "Iris Button" //Iris Care Pendant + fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0402, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model: "3460-L", deviceJoinName: "Iris Button" //Iris Smart Button } simulator {} diff --git a/devicetypes/smartthings/zigbee-co-sensor.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-co-sensor.src/i18n/messages.properties new file mode 100755 index 00000000000..27b208036d7 --- /dev/null +++ b/devicetypes/smartthings/zigbee-co-sensor.src/i18n/messages.properties @@ -0,0 +1,17 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Carbon Monoxide Sensor'''.zh-cn=海曼一氧化碳报警器 +'''HEIMAN CO Sensor'''.zh-cn=海曼一氧化碳报警器 diff --git a/devicetypes/smartthings/zigbee-co-sensor.src/zigbee-co-sensor.groovy b/devicetypes/smartthings/zigbee-co-sensor.src/zigbee-co-sensor.groovy old mode 100644 new mode 100755 index 1de185dc7cb..fe0e0b176ee --- a/devicetypes/smartthings/zigbee-co-sensor.src/zigbee-co-sensor.groovy +++ b/devicetypes/smartthings/zigbee-co-sensor.src/zigbee-co-sensor.groovy @@ -28,8 +28,9 @@ metadata { capability "Refresh" capability "Health Check" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "CO_00.00.00.22TC", deviceJoinName: "Ozom Smart Carbon Monoxide Sensor", mnmn: "SmartThings", vid: "generic-carbon-monoxide" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "CO_00.00.00.15TC", deviceJoinName: "Ozom Smart Carbon Monoxide Sensor", mnmn: "SmartThings", vid: "generic-carbon-monoxide" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "CO_00.00.00.22TC", deviceJoinName: "Ozom Carbon Monoxide Sensor", mnmn: "SmartThings", vid: "generic-carbon-monoxide" //Ozom Smart Carbon Monoxide Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "CO_00.00.00.15TC", deviceJoinName: "Ozom Carbon Monoxide Sensor", mnmn: "SmartThings", vid: "generic-carbon-monoxide" //Ozom Smart Carbon Monoxide Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500", outClusters: "0000", manufacturer: "HEIMAN", model: "COSensor-EM", deviceJoinName: "HEIMAN Carbon Monoxide Sensor" //HEIMAN CO Sensor } tiles { diff --git a/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy b/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy index cd604de6484..6c7bc321119 100644 --- a/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy +++ b/devicetypes/smartthings/zigbee-dimmer-power.src/zigbee-dimmer-power.groovy @@ -25,15 +25,15 @@ metadata { capability "Light" // Generic - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04", deviceJoinName: "Light" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702", deviceJoinName: "Light" // GE/Jasco - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45852", deviceJoinName: "GE Zigbee Plug-In Dimmer", ocfDeviceType: "oic.d.smartplug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45857", deviceJoinName: "GE Zigbee In-Wall Dimmer", ocfDeviceType: "oic.d.switch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45852", deviceJoinName: "GE Dimmer Switch", ocfDeviceType: "oic.d.smartplug" //GE Zigbee Plug-In Dimmer + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45857", deviceJoinName: "GE Dimmer Switch", ocfDeviceType: "oic.d.switch" //GE Zigbee In-Wall Dimmer // Sengled - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-CIA19NAE26", deviceJoinName: "Sengled Element touch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-CIA19NAE26", deviceJoinName: "Sengled Light" //Sengled Element touch } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zigbee-dimmer-with-motion-sensor.src/zigbee-dimmer-with-motion-sensor.groovy b/devicetypes/smartthings/zigbee-dimmer-with-motion-sensor.src/zigbee-dimmer-with-motion-sensor.groovy index 8f9147a89b5..7dd19e07a67 100644 --- a/devicetypes/smartthings/zigbee-dimmer-with-motion-sensor.src/zigbee-dimmer-with-motion-sensor.groovy +++ b/devicetypes/smartthings/zigbee-dimmer-with-motion-sensor.src/zigbee-dimmer-with-motion-sensor.groovy @@ -24,7 +24,7 @@ metadata { capability "Motion Sensor" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0500, 0702, 0B05, FC01", outClusters: "0019", manufacturer: "sengled", model: "E13-N11", deviceJoinName: "Sengled Smart LED with Motion Sensor PAR38 Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0500, 0702, 0B05, FC01", outClusters: "0019", manufacturer: "sengled", model: "E13-N11", deviceJoinName: "Sengled Light" //Sengled Smart LED with Motion Sensor PAR38 Bulb } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zigbee-dimmer.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-dimmer.src/i18n/messages.properties index 8006c3c1d9d..0a55de6fa84 100755 --- a/devicetypes/smartthings/zigbee-dimmer.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-dimmer.src/i18n/messages.properties @@ -13,4 +13,5 @@ # under the License. # Chinese +'''Light'''.zh-cn=智能球泡灯 '''Smart Bulb'''.zh-cn=智能球泡灯 diff --git a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy index acd8587ff9b..2cd9d152fb2 100644 --- a/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy +++ b/devicetypes/smartthings/zigbee-dimmer.src/zigbee-dimmer.groovy @@ -23,89 +23,109 @@ metadata { capability "Light" // Generic - fingerprint profileId: "0104", deviceId: "0101", inClusters: "0006, 0008", deviceJoinName: "Generic Dimmable Light" + fingerprint profileId: "0104", deviceId: "0101", inClusters: "0006, 0008", deviceJoinName: "Light" //Generic Dimmable Light // AduroSmart - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", deviceId: "0101", manufacturer: "AduroSmart Eria", model: "AD-DimmableLight3001", deviceJoinName: "Eria ZigBee Dimmable Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", deviceId: "0101", manufacturer: "AduroSmart Eria", model: "AD-DimmableLight3001", deviceJoinName: "Eria Light" //Eria ZigBee Dimmable Bulb // Aurora - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "LCBulb01UK", deviceJoinName: "Aurora AOne Control Dimmer (120w)", ocfDeviceType: "oic.d.switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0003", manufacturer: "Aurora", model: "Dimmer", deviceJoinName: "Aurora AOne Control Dimmer (320w)", ocfDeviceType: "oic.d.switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0009", outClusters: "0019", manufacturer: "Aurora", model: "FWMPROZXBulb50AU", deviceJoinName: "Aurora MPro" - fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, FFFF, 1000", outClusters: "0019", manufacturer: "Aurora", model: "FWBulb51AU", deviceJoinName: "Aurora Smart Dimmable" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "FWStrip50AU", deviceJoinName: "Aurora Dimmable Strip Controller" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWGU10Bulb50AU", deviceJoinName: "Aurora Smart Dimmable GU10" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "NPD3032", deviceJoinName: "Aurora In-line Dimmer", ocfDeviceType: "oic.d.switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "WallDimmerMaster", deviceJoinName: "Aurora Smart Rotary Dimmer", ocfDeviceType: "oic.d.switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05 ,1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWST64Bulb50AU", deviceJoinName: "Aurora Dimmable Filament Vintage ST64" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05 ,1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWG125Bulb50AU", deviceJoinName: "Aurora Dimmable Filament Vintage G125" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05 ,1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWA60Bulb50AU", deviceJoinName: "Aurora Dimmable Filament Vintage GLS" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "LCBulb01UK", deviceJoinName: "AOne Dimmer Switch", ocfDeviceType: "oic.d.switch" //Aurora AOne Control Dimmer (120w) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0003", manufacturer: "Aurora", model: "Dimmer", deviceJoinName: "AOne Dimmer Switch", ocfDeviceType: "oic.d.switch" //Aurora AOne Control Dimmer (320w) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0009", outClusters: "0019", manufacturer: "Aurora", model: "FWMPROZXBulb50AU", deviceJoinName: "Aurora Light" //Aurora MPro + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, FFFF, 1000", outClusters: "0019", manufacturer: "Aurora", model: "FWBulb51AU", deviceJoinName: "Aurora Light" //Aurora Smart Dimmable + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "FWStrip50AU", deviceJoinName: "Aurora Light" //Aurora Dimmable Strip Controller + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWGU10Bulb50AU", deviceJoinName: "Aurora Light" //Aurora Smart Dimmable GU10 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "NPD3032", deviceJoinName: "Aurora Dimmer Switch", ocfDeviceType: "oic.d.switch" //Aurora In-line Dimmer + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "WallDimmerMaster", deviceJoinName: "Aurora Dimmer Switch", ocfDeviceType: "oic.d.switch" //Aurora Smart Rotary Dimmer + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05 ,1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWST64Bulb50AU", deviceJoinName: "Aurora Light" //Aurora Dimmable Filament Vintage ST64 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05 ,1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWG125Bulb50AU", deviceJoinName: "Aurora Light" //Aurora Dimmable Filament Vintage G125 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05 ,1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWA60Bulb50AU", deviceJoinName: "Aurora Light" //Aurora Dimmable Filament Vintage GLS + + //CWD + // raw description "01 0104 0101 01 09 0000 0003 0004 0005 0006 0008 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.A806Edim-A001", deviceJoinName: "CWD Light" //model: "E27 dim", brand: "Collingwood" + // raw description "01 0104 0101 01 09 0000 0003 0004 0005 0006 0008 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.A806Bdim-A001", deviceJoinName: "CWD Light" //model: "BC dim", brand: "Collingwood" + // raw description "01 0104 0101 01 09 0000 0003 0004 0005 0006 0008 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.M350dim-A001", deviceJoinName: "CWD Light" //model: "GU10 dim", brand: "Collingwood" + + // IKEA + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WW 806lm", deviceJoinName: "IKEA Light" // raw description 01 0104 0101 01 07 0000 0003 0004 0005 0006 0008 1000 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WW clear 250lm", deviceJoinName: "IKEA Light" //raw desc: 01 0104 0101 01 07 0000 0003 0004 0005 0006 0008 1000 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb // INGENIUM - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0301, FC01", manufacturer: "ubisys", model: "D1 (5503)", deviceJoinName: "INGENIUM ZB Universal Dimming Module ZBM01d" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Megaman", model: "AD-DimmableLight3001", deviceJoinName: "INGENIUM ZB LED Classic" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0301, FC01", manufacturer: "ubisys", model: "D1 (5503)", deviceJoinName: "INGENIUM Light" //INGENIUM ZB Universal Dimming Module ZBM01d + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Megaman", model: "AD-DimmableLight3001", deviceJoinName: "INGENIUM Light" //INGENIUM ZB LED Classic // Innr - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019", manufacturer: "innr", model: "RF 263", deviceJoinName: "Innr Smart Filament Bulb Vintage" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019", manufacturer: "innr", model: "BF 263", deviceJoinName: "Innr Smart Filament Bulb Vintage" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019", manufacturer: "innr", model: "BF 265", deviceJoinName: "Innr Smart Filament Bulb" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0019", manufacturer: "innr", model: "AE 260", deviceJoinName: "Innr Smart Bulb" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0019", manufacturer: "innr", model: "BE 220", deviceJoinName: "Innr Smart Flood Light White" - fingerprint manufacturer: "innr", model: "RF 265", deviceJoinName: "Innr Smart Filament Bulb White" // raw description: 01 0104 0101 01 09 0000 0003 0004 0005 0006 0008 0B05 1000 FC82 01 0019 - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 265", deviceJoinName: "Innr Smart Bulb White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 245", deviceJoinName: "Innr Smart Candle White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RS 225", deviceJoinName: "Innr Smart Spot White" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019", manufacturer: "innr", model: "RF 263", deviceJoinName: "Innr Light" //Innr Smart Filament Bulb Vintage + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019", manufacturer: "innr", model: "BF 263", deviceJoinName: "Innr Light" //Innr Smart Filament Bulb Vintage + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019", manufacturer: "innr", model: "BF 265", deviceJoinName: "Innr Light" //Innr Smart Filament Bulb + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0019", manufacturer: "innr", model: "AE 260", deviceJoinName: "Innr Light" //Innr Smart Bulb + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0019", manufacturer: "innr", model: "BE 220", deviceJoinName: "Innr Light" //Innr Smart Flood Light White + fingerprint manufacturer: "innr", model: "RF 265", deviceJoinName: "Innr Light" // raw description: 01 0104 0101 01 09 0000 0003 0004 0005 0006 0008 0B05 1000 FC82 01 0019 //Innr Smart Filament Bulb White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 265", deviceJoinName: "Innr Light" //Innr Smart Bulb White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 245", deviceJoinName: "Innr Light" //Innr Smart Candle White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RS 225", deviceJoinName: "Innr Light" //Innr Smart Spot White + fingerprint manufacturer: "innr", model: "RF 261", deviceJoinName: "Innr Light" // Innr Smart filament globe vintage E27 (RF 261) profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019" //Light + fingerprint manufacturer: "innr", model: "RF 264", deviceJoinName: "Innr Light" // Innr Smart filament edison vintage E27 (RF 264) profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "0019" //Light // Leedarson - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Smarthome", model: "S111-201A", deviceJoinName: "Leedarson Dimmable White Bulb A19" - fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, FFFF, 1000", outClusters: "0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS0000", deviceJoinName: "Smart Bulb" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "LDS", model: "ZHA-DIMLight-GLS0000", deviceJoinName: "Smart Bulb" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS", deviceJoinName: "Smart Bulb" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS0044", deviceJoinName: "Smart Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Smarthome", model: "S111-201A", deviceJoinName: "Leedarson Light" //Leedarson Dimmable White Bulb A19 + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, FFFF, 1000", outClusters: "0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS0000", deviceJoinName: "Light" //Smart Bulb + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "LDS", model: "ZHA-DIMLight-GLS0000", deviceJoinName: "Light" //Smart Bulb + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS", deviceJoinName: "Light" //Smart Bulb + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS0044", deviceJoinName: "Light" //Smart Bulb // Leviton - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL6HD", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL3HL", deviceJoinName: "Leviton Lumina RF Plug-In Dimmer", ocfDeviceType: "oic.d.switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL1KD", deviceJoinName: "Leviton Lumina RF Dimmer Switch", ocfDeviceType: "oic.d.switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "ZSD07", deviceJoinName: "Leviton Lumina RF 0-10V Dimming Wall Switch", ocfDeviceType: "oic.d.switch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL6HD", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.switch" //Leviton Dimmer Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL3HL", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.switch" //Leviton Lumina RF Plug-In Dimmer + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL1KD", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.switch" //Leviton Lumina RF Dimmer Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "ZSD07", deviceJoinName: "Leviton Dimmer Switch", ocfDeviceType: "oic.d.switch" //Leviton Lumina RF 0-10V Dimming Wall Switch + + // LINKIND + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "lk", model: "ZBT-DIMLight-GLS0010", deviceJoinName: "Linkind Light" //Linkind Dimmable A19 Bulb // Müller Licht - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "MLI", model: "ZBT-DimmableLight", deviceJoinName: "Müller Licht Tint Bulb Dimming" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "MLI", model: "ZBT-DimmableLight", deviceJoinName: "Tint Light" //Müller Licht Tint Bulb Dimming // OSRAM/Sylvania - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart A19 Soft White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM 10 Year", deviceJoinName: "SYLVANIA Smart 10-Year A19" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart BR30 Soft White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "A19 W 10 year", deviceJoinName: "SYLVANIA Smart 10Y A19 Soft White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "BR30 W 10 year", deviceJoinName: "SYLVANIA Smart 10Y BR30 Soft White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "PAR38 W 10 year", deviceJoinName: "SYLVANIA Smart 10Y PAR38 Soft White" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart A19 Soft White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM 10 Year", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart 10-Year A19 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "SYLVANIA Light" //Sylvania Ultra iQ + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart PAR38 Soft White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR ON/OFF/DIM", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart BR30 Soft White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "A19 W 10 year", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart 10Y A19 Soft White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "BR30 W 10 year", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart 10Y BR30 Soft White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "PAR38 W 10 year", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart 10Y PAR38 Soft White // Ozom - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "LEEDARSON LIGHTING", model: "M350ST-W1R-01", deviceJoinName: "OZOM Dimmable LED Smart Light" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "LEEDARSON LIGHTING", model: "M350ST-W1R-01", deviceJoinName: "OZOM Light" //OZOM Dimmable LED Smart Light // Sengled - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G13", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G14", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G23", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G33", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E12-N13", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E12-N14", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E12-N15", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N13", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N14", deviceJoinName: "Sengled Element Classic" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E1A-AC2", deviceJoinName: "Sengled DownLight" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N13A", deviceJoinName: "Sengled Extra Bright Soft White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N14A", deviceJoinName: "Sengled Extra Bright Daylight" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E21-N13A", deviceJoinName: "Sengled Soft White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E21-N14A", deviceJoinName: "Sengled Daylight" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G13", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G14", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G23", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-G33", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E12-N13", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E12-N14", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E12-N15", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N13", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N14", deviceJoinName: "Sengled Light" //Sengled Element Classic + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E1A-AC2", deviceJoinName: "Sengled Light" //Sengled DownLight + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N13A", deviceJoinName: "Sengled Light" //Sengled Extra Bright Soft White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N14A", deviceJoinName: "Sengled Light" //Sengled Extra Bright Daylight + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E21-N13A", deviceJoinName: "Sengled Light" //Sengled Soft White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E21-N14A", deviceJoinName: "Sengled Light" //Sengled Daylight + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-U21U31", deviceJoinName: "Sengled Light" //Sengled Element Touch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05, FC01", outClusters: "0019", manufacturer: "sengled", model: "E13-A21", deviceJoinName: "Sengled Light" //Sengled LED Flood Light + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N1G", deviceJoinName: "Sengled Light" //Sengled Smart LED Vintage Edison Bulb // SmartThings - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS0006", deviceJoinName: "Smart Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "LDS", model: "ZBT-DIMLight-GLS0006", deviceJoinName: "Light" //Smart Bulb // Wemo - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Light" //Wemo Bulb } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy b/devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy index 0bccfbddf7d..1844303ae48 100644 --- a/devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy +++ b/devicetypes/smartthings/zigbee-lock-without-codes.src/zigbee-lock-without-codes.groovy @@ -26,8 +26,8 @@ metadata { capability "Configuration" capability "Health Check" - fingerprint profileId:"0104, 000A", inClusters:"0000, 0001, 0003, 0009, 0020,0101, 0B05", outclusters:"000A, 0019, 0B05", manufacturer:"Danalock", model:"V3-BTZB", deviceJoinName:"Danalock V3 Smart Lock" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0500, 0101", outClusters: "0019", model: "E261-KR0B0Z0-HA", deviceJoinName: "C2O Lock", mnmn: "SmartThings", vid: "C2O-ZigBee-Lock" + fingerprint profileId:"0104, 000A", inClusters:"0000, 0001, 0003, 0009, 0020,0101, 0B05", outclusters:"000A, 0019, 0B05", manufacturer:"Danalock", model:"V3-BTZB", deviceJoinName:"Danalock Door Lock" //Danalock V3 Smart Lock + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0500, 0101", outClusters: "0019", model: "E261-KR0B0Z0-HA", deviceJoinName: "C2O Door Lock", mnmn: "SmartThings", vid: "C2O-ZigBee-Lock" //C2O Lock } @@ -207,6 +207,15 @@ private def parseAttributeResponse(String description) { responseMap.value = "unknown" responseMap.descriptionText = "Unknown state" } + if (responseMap.value) { + /* delay this event for a second in the hopes that we get the operation event (which has more info). + If we don't get one, then it's okay to send. If we send the event with more info first, the event + with less info will be marked as not displayed + */ + log.debug "Lock attribute report received: ${responseMap.value}. Delaying event." + runIn(1, "delayLockEvent", [data : [map : responseMap]]) + return [:] + } } else { return null } @@ -214,6 +223,11 @@ private def parseAttributeResponse(String description) { return result } +def delayLockEvent(data) { + log.debug "Sending cached lock operation: ${data.map}" + sendEvent(data.map) +} + private def parseIasMessage(String description) { ZoneStatus zs = zigbee.parseZoneStatus(description) def responseMap = [ name: "battery", value: zs.isBatterySet() ? 5 : 55] diff --git a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy index e05626962c3..705d444e569 100644 --- a/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy +++ b/devicetypes/smartthings/zigbee-lock.src/zigbee-lock.groovy @@ -27,23 +27,27 @@ metadata { capability "Configuration" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000,0001,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL220 TS LL", deviceJoinName: "Yale Touch Screen Lever Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Assure Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020,0B05", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226 TSDB", deviceJoinName: "Yale Assure Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020,0B05", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD446 BLE TSDB", deviceJoinName: "Yale Assure Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD216 PBDB", deviceJoinName: "Yale Push Button Deadbolt Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL226 TSLL", deviceJoinName: "Yale Assure Touch Screen Lever Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020,0B05", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL216 PB", deviceJoinName: "Yale Assure Keypad Lever Lock" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_5", deviceJoinName: "Kwikset 5-Button Deadbolt" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10", deviceJoinName: "Kwikset 10-Button Deadbolt" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10T", deviceJoinName: "Kwikset 10-Button Touch Deadbolt" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0101", manufacturer:"Kwikset", model:"Smartcode", deviceJoinName: "Kwikset Smartcode Lock" - fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0009, 0020, 0101, 0B05, FC00", outClusters: "000A, 0019", manufacturer: "Schlage", model: "BE468", deviceJoinName: "Schlage Connect Smart Deadbolt" + fingerprint profileId: "0104", inClusters: "0000,0001,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Door Lock" //Yale Touch Screen Deadbolt Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL220 TS LL", deviceJoinName: "Yale Door Lock" //Yale Touch Screen Lever Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Door Lock" //Yale Push Button Deadbolt Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Door Lock" //Yale Touch Screen Deadbolt Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Door Lock" //Yale Push Button Lever Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Door Lock" //Yale Assure Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020,0B05", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226 TSDB", deviceJoinName: "Yale Door Lock" //Yale Assure Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020,0B05", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD446 BLE TSDB", deviceJoinName: "Yale Door Lock" //Yale Assure Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD216 PBDB", deviceJoinName: "Yale Door Lock" //Yale Push Button Deadbolt Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL226 TSLL", deviceJoinName: "Yale Door Lock" //Yale Assure Touch Screen Lever Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020,0B05", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL216 PB", deviceJoinName: "Yale Door Lock" //Yale Assure Keypad Lever Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_5", deviceJoinName: "Kwikset Door Lock" //Kwikset 5-Button Deadbolt + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset Door Lock" //Kwikset 5-Button Lever + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10", deviceJoinName: "Kwikset Door Lock" //Kwikset 10-Button Deadbolt + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_10T", deviceJoinName: "Kwikset Door Lock" //Kwikset 10-Button Touch Deadbolt + fingerprint profileId: "0104", inClusters: "0000, 0003, 0101", manufacturer:"Kwikset", model:"Smartcode", deviceJoinName: "Kwikset Door Lock" //Kwikset Smartcode Lock + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0009, 0020, 0101, 0B05, FC00", outClusters: "000A, 0019", manufacturer: "Schlage", model: "BE468", deviceJoinName: "Schlage Door Lock" //Schlage Connect Smart Deadbolt + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020,0B05", outClusters: "000A,0019", manufacturer: "Yale", model: "YDD-D4F0 TSDB", deviceJoinName: "Lockwood Door Lock" //Lockwood Smart Lock + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "iZBModule01", deviceJoinName: "Yale Door Lock" //Yale Locks (YDF30/40, YMF30/40) with old firmware (v.9.0) + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "c700000202", deviceJoinName: "Yale Door Lock" //Yale Fingerprint Lock YDF40 + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,000A,0020,0101", outClusters: "000A,0019", manufacturer: "ASSA ABLOY iRevo", model: "0700000001", deviceJoinName: "Yale Door Lock" //Yale Fingerprint Lock YMF40 } tiles(scale: 2) { @@ -492,6 +496,15 @@ private def parseAttributeResponse(String description) { responseMap.value = "unknown" responseMap.descriptionText = "Unknown state" } + if (responseMap.value) { + /* delay this event for a second in the hopes that we get the operation event (which has more info). + If we don't get one, then it's okay to send. If we send the event with more info first, the event + with less info will be marked as not displayed + */ + log.debug "Lock attribute report received: ${responseMap.value}. Delaying event." + runIn(1, "delayLockEvent", [data : [map : responseMap]]) + return [:] + } } else if (clusterInt == CLUSTER_DOORLOCK && attrInt == DOORLOCK_ATTR_MIN_PIN_LENGTH && descMap.value) { def minCodeLength = Integer.parseInt(descMap.value, 16) responseMap = [name: "minCodeLength", value: minCodeLength, descriptionText: "Minimum PIN length is ${minCodeLength}", displayed: false] @@ -516,6 +529,11 @@ private def parseAttributeResponse(String description) { return result } +def delayLockEvent(data) { + log.debug "Sending cached lock operation: ${data.map}" + sendEvent(data.map) +} + /** * Responsible for handling command responses * diff --git a/devicetypes/smartthings/zigbee-metering-plug.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-metering-plug.src/i18n/messages.properties index f5405decff8..25779c2b6e3 100755 --- a/devicetypes/smartthings/zigbee-metering-plug.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-metering-plug.src/i18n/messages.properties @@ -13,5 +13,10 @@ # under the License. # Chinese +'''HONYAR Outlet'''.zh-cn=鸿雁智能插座 (USB) +'''HONYAR Outlet (USB)'''.zh-cn=鸿雁智能插座 (USB) '''HONYAR Smart Outlet (USB)'''.zh-cn=鸿雁智能插座 (USB) +'''HONYAR Outlet'''.zh-cn=鸿雁智能插座 '''HONYAR Smart Outlet'''.zh-cn=鸿雁智能插座 +'''HEIMAN Outlet'''.zh-cn=海曼智能墙面插座 +'''HEIMAN Smart Outlet'''.zh-cn=海曼智能墙面插座 diff --git a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy old mode 100755 new mode 100644 index fa727bf40ce..e2e81d2b622 --- a/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy +++ b/devicetypes/smartthings/zigbee-metering-plug.src/zigbee-metering-plug.groovy @@ -24,11 +24,20 @@ metadata { capability "Sensor" capability "Configuration" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0702, FC82", outClusters: "0003, 000A, 0019", manufacturer: "LDS", model: "ZB-ONOFFPlug-D0000", deviceJoinName: "Smart Plug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0702, FC82", outClusters: "0003, 000A, 0019", manufacturer: "LDS", model: "ZB-ONOFFPlug-D0005", deviceJoinName: "Smart Plug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0105", deviceJoinName: "HONYAR Smart Outlet (USB)" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0104", deviceJoinName: "HONYAR Smart Outlet" - } + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0702, FC82", outClusters: "0003, 000A, 0019", manufacturer: "LDS", model: "ZB-ONOFFPlug-D0000", deviceJoinName: "Outlet" //Smart Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0702, FC82", outClusters: "0003, 000A, 0019", manufacturer: "LDS", model: "ZB-ONOFFPlug-D0005", deviceJoinName: "Outlet" //Smart Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0105", deviceJoinName: "HONYAR Outlet" //HONYAR Smart Outlet (USB) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", outClusters: "0003", manufacturer: "REXENSE", model: "HY0104", deviceJoinName: "HONYAR Outlet" //HONYAR Smart Outlet + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0009, 0702, 0B04", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "E_Socket", deviceJoinName: "HEIMAN Outlet" //HEIMAN Smart Outlet + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0702, FC82", outClusters: "0003, 000A, 0019", manufacturer: "sengled", model: "E1C-NB7", deviceJoinName: "Sengled Outlet" //Sengled Smart Plug with Energy Tracker + fingerprint manufacturer: "DAWON_DNS", model: "PM-B430-ZB", deviceJoinName: "Dawon Outlet" // DAWON DNS Smart Plug PM-B430-ZB (10A), raw description: 01 0104 0051 01 07 0000, 0004, 0003, 0006, 0019, 0702, 0B04 07 0000, 0004, 0003, 0006, 0019, 0702, 0B04 + fingerprint manufacturer: "DAWON_DNS", model: "PM-B530-ZB", deviceJoinName: "Dawon Outlet" // DAWON DNS Smart Plug PM-B530-ZB (16A), raw description: 01 0104 0051 01 07 0000, 0004, 0003, 0006, 0019, 0702, 0B04 07 0000, 0004, 0003, 0006, 0019, 0702, 0B04 + fingerprint manufacturer: "DAWON_DNS", model: "PM-C140-ZB", deviceJoinName: "Dawon Outlet" // DAWON DNS In-Wall Outlet PM-C140-ZB, raw description: 01 0104 0051 01 0A 0000 0002 0003 0004 0006 0019 0702 0B04 0008 0009 0A 0000 0002 0003 0004 0006 0019 0702 0B04 0008 0009 + fingerprint profileId: "0104", inClusters: "0000, 0002, 0003, 0006, 0702, 0B04", outClusters: "0003, 0019", manufacturer: "DAWON_DNS", model: "PM-B540-ZB", deviceJoinName: "Dawon Outlet" // DAWON DNS Smart Plug + fingerprint profileId: "0104", inClusters: "0000, 0002, 0003, 0006, 0702, 0B04", outClusters: "0003, 0019", manufacturer: "DAWON_DNS", model: "ST-B550-ZB", deviceJoinName: "Dawon Outlet" // DAWON DNS Smart Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0006, 0702, 0B04", outClusters: "0003, 0019", manufacturer: "DAWON_DNS", model: "PM-C150-ZB", deviceJoinName: "Dawon Outlet" // DAWON DNS In-Wall Outlet + fingerprint profileId: "0104", inClusters: "0000, 0003, 0006, 0702, 0B04", outClusters: "0003, 0019", manufacturer: "DAWON_DNS", model: "PM-C250-ZB", deviceJoinName: "Dawon Outlet" // DAWON DNS In-Wall Outlet + } tiles(scale: 2){ multiAttributeTile(name:"switch", type: "generic", width: 6, height: 4, canChangeIcon: true){ @@ -61,23 +70,24 @@ def getATTRIBUTE_HISTORICAL_CONSUMPTION() { 0x0400 } def parse(String description) { log.debug "description is $description" def event = zigbee.getEvent(description) - def powerDiv = 1 - def energyDiv = 100 + def descMap = zigbee.parseDescriptionAsMap(description) if (event) { log.info "event enter:$event" - if (event.name== "power") { - event.value = event.value/powerDiv + if (event.name == "switch" && !descMap.isClusterSpecific && descMap.commandInt == 0x0B) { + log.info "Ignoring default response with desc map: $descMap" + return [:] + } else if (event.name== "power") { + event.value = event.value/getPowerDiv() event.unit = "W" } else if (event.name== "energy") { - event.value = event.value/energyDiv + event.value = event.value/getEnergyDiv() event.unit = "kWh" } log.info "event outer:$event" sendEvent(event) } else { List result = [] - def descMap = zigbee.parseDescriptionAsMap(description) log.debug "Desc Map: $descMap" List attrData = [[clusterInt: descMap.clusterInt ,attrInt: descMap.attrInt, value: descMap.value]] @@ -90,13 +100,13 @@ def parse(String description) { if (it.value && it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_HISTORICAL_CONSUMPTION) { log.debug "power" map.name = "power" - map.value = zigbee.convertHexToInt(it.value)/powerDiv + map.value = zigbee.convertHexToInt(it.value)/getPowerDiv() map.unit = "W" } else if (it.value && it.clusterInt == zigbee.SIMPLE_METERING_CLUSTER && it.attrInt == ATTRIBUTE_READING_INFO_SET) { log.debug "energy" map.name = "energy" - map.value = zigbee.convertHexToInt(it.value)/energyDiv + map.value = zigbee.convertHexToInt(it.value)/getEnergyDiv() map.unit = "kWh" } @@ -110,11 +120,20 @@ def parse(String description) { } def off() { - zigbee.off() + def cmds = zigbee.off() + if (device.getDataValue("model") == "HY0105") { + cmds += zigbee.command(zigbee.ONOFF_CLUSTER, 0x00, "", [destEndpoint: 0x02]) + } + return cmds } + def on() { - zigbee.on() + def cmds = zigbee.on() + if (device.getDataValue("model") == "HY0105") { + cmds += zigbee.command(zigbee.ONOFF_CLUSTER, 0x01, "", [destEndpoint: 0x02]) + } + return cmds } /** @@ -138,5 +157,28 @@ def configure() { return refresh() + zigbee.onOffConfig() + zigbee.configureReporting(zigbee.SIMPLE_METERING_CLUSTER, ATTRIBUTE_READING_INFO_SET, DataType.UINT48, 1, 600, 1) + - zigbee.electricMeasurementPowerConfig(1, 600, 1) + zigbee.electricMeasurementPowerConfig(1, 600, 1) + + zigbee.simpleMeteringPowerConfig() +} + +private int getPowerDiv() { + isSengledOutlet() ? 10 : 1 +} + +private int getEnergyDiv() { + if (isDawonOutlet()) { + 1000 + } else if (isSengledOutlet()) { + 10000 + } else { + 100 + } +} + +private boolean isSengledOutlet() { + device.getDataValue("model") == "E1C-NB7" +} + +private boolean isDawonOutlet() { + device.getDataValue("manufacturer") == "DAWON_DNS" } diff --git a/devicetypes/smartthings/zigbee-motion-detector.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-motion-detector.src/i18n/messages.properties new file mode 100755 index 00000000000..3ba91371b27 --- /dev/null +++ b/devicetypes/smartthings/zigbee-motion-detector.src/i18n/messages.properties @@ -0,0 +1,15 @@ +# Copyright 2019 SmartThings +# +# 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. +# Chinese +'''HEIMAN Motion Sensor'''.zh-cn=海曼人体红外传感器 diff --git a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy index 33a17429a4d..23c5d2d2d0d 100644 --- a/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy +++ b/devicetypes/smartthings/zigbee-motion-detector.src/zigbee-motion-detector.groovy @@ -25,9 +25,10 @@ metadata { capability "Refresh" capability "Health Check" capability "Sensor" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500", outClusters: "0003", manufacturer: "eWeLink", model: "MS01", deviceJoinName: "eWeLink Motion Sensor" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer:"ORVIBO", model:"895a2d80097f4ae2b2d40500d5e03dcc", deviceJoinName: "Orvibo Motion Sensor" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer:"Megaman", model:"PS601/z1", deviceJoinName: "INGENIUM ZB PIR Sensor" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500", outClusters: "0003", manufacturer: "eWeLink", model: "MS01", deviceJoinName: "eWeLink Motion Sensor" //eWeLink Motion Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001", manufacturer: "ORVIBO", model: "895a2d80097f4ae2b2d40500d5e03dcc", deviceJoinName: "Orvibo Motion Sensor" //Orvibo Motion Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0003,0500,0001,FFFF", manufacturer: "Megaman", model: "PS601/z1", deviceJoinName: "INGENIUM Motion Sensor" //INGENIUM ZB PIR Sensor + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000, 0003, 0500, 0001", outClusters: "0019", manufacturer: "HEIMAN", model: "PIRSensor-N", deviceJoinName: "HEIMAN Motion Sensor" //HEIMAN Motion Sensor } simulator { status "active": "zone status 0x0001 -- extended status 0x00" diff --git a/devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/i18n/messages.properties new file mode 100644 index 00000000000..f02619ca619 --- /dev/null +++ b/devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/i18n/messages.properties @@ -0,0 +1,207 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +'''Enter a percentage to adjust the humidity.'''.en=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-gb=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-us=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.en-ca=Enter a percentage to adjust the humidity. +'''Enter a percentage to adjust the humidity.'''.sq=Fut një përqindje për të përshtatur lagështinë. +'''Enter a percentage to adjust the humidity.'''.ar=أدخل نسبة مئوية لتعديل الرطوبة. +'''Enter a percentage to adjust the humidity.'''.be=Увядзіце працэнт, каб адрэгуляваць вільготнасць. +'''Enter a percentage to adjust the humidity.'''.sr-ba=Unesite procenat da prilagodite vlažnost. +'''Enter a percentage to adjust the humidity.'''.bg=Въведете процент, за да регулирате влажността. +'''Enter a percentage to adjust the humidity.'''.ca=Introdueix un percentatge per ajustar la humitat. +'''Enter a percentage to adjust the humidity.'''.zh-cn=请输入百分比来调整湿度。 +'''Enter a percentage to adjust the humidity.'''.zh-hk=輸入百分比以調整濕度。 +'''Enter a percentage to adjust the humidity.'''.zh-tw=請輸入百分比來調整濕度。 +'''Enter a percentage to adjust the humidity.'''.hr=Unesite postotak za promjenu vlažnosti. +'''Enter a percentage to adjust the humidity.'''.cs=Upravte vlhkost zadáním procenta. +'''Enter a percentage to adjust the humidity.'''.da=Angiv en procentsats for at justere fugtigheden. +'''Enter a percentage to adjust the humidity.'''.nl=Voer een percentage in om de vochtigheid aan te passen. +'''Enter a percentage to adjust the humidity.'''.et=Sisestage protsent, et muuta niiskust. +'''Enter a percentage to adjust the humidity.'''.fi=Anna prosentti kosteuden säätämistä varten. +'''Enter a percentage to adjust the humidity.'''.fr=Entrez un pourcentage pour ajuster l'humidité. +'''Enter a percentage to adjust the humidity.'''.de=Geben Sie einen Prozentsatz ein, um die Feuchtigkeit anzupassen. +'''Enter a percentage to adjust the humidity.'''.el=Εισαγάγετε ποσοστό για την προσαρμογή της υγρασίας. +'''Enter a percentage to adjust the humidity.'''.iw=כדי להתאים רמת לחות, הזן אחוז. +'''Enter a percentage to adjust the humidity.'''.hi-in=नमी समायोजित करने के लिए, प्रतिशत प्रविष्ट करें। +'''Enter a percentage to adjust the humidity.'''.hu=A páratartalom beállításához adjon meg egy százalékos értéket. +'''Enter a percentage to adjust the humidity.'''.is=Sláðu inn prósentu til að stilla rakastigið. +'''Enter a percentage to adjust the humidity.'''.in=Masukkan persentase untuk mengatur kelembapan. +'''Enter a percentage to adjust the humidity.'''.it=Inserite una percentuale per regolare l'umidità. +'''Enter a percentage to adjust the humidity.'''.ja=湿度を調整するパーセンテージを入力してください。 +'''Enter a percentage to adjust the humidity.'''.ko=원하는 습도율을 입력하고 실내 습도를 설정해 보세요. +'''Enter a percentage to adjust the humidity.'''.lv=Ievadiet procentuālo daudzumu, lai pielāgotu mitruma līmeni. +'''Enter a percentage to adjust the humidity.'''.lt=Įveskite procentus ir sureguliuokite drėgnumą. +'''Enter a percentage to adjust the humidity.'''.ms=Masukkan peratusan untuk melaraskan kelembapan. +'''Enter a percentage to adjust the humidity.'''.no=Angi en prosent for å justere fuktigheten. +'''Enter a percentage to adjust the humidity.'''.pl=Wprowadź procent, aby ustawić wilgotność. +'''Enter a percentage to adjust the humidity.'''.pt=Introduzir uma percentagem para ajustar a humidade. +'''Enter a percentage to adjust the humidity.'''.ro=Introduceți un procent pentru ajustarea umidității. +'''Enter a percentage to adjust the humidity.'''.ru=Введите процент для регулировки влажности. +'''Enter a percentage to adjust the humidity.'''.sr=Unesite procenat da biste prilagodili vlažnost. +'''Enter a percentage to adjust the humidity.'''.sk=Upravte vlhkosť zadaním percenta. +'''Enter a percentage to adjust the humidity.'''.sl=Vnesite odstotek, da prilagodite vlažnost. +'''Enter a percentage to adjust the humidity.'''.es=Introduce un porcentaje para ajustar la humedad. +'''Enter a percentage to adjust the humidity.'''.sv=Ange ett procenttal när du vill justera fuktigheten. +'''Enter a percentage to adjust the humidity.'''.th=ใส่เปอร์เซ็นต์เพื่อปรับความชื้น +'''Enter a percentage to adjust the humidity.'''.tr=Nemi ayarlamak için bir yüzde değeri girin. +'''Enter a percentage to adjust the humidity.'''.uk=Уведіть відсоток для регулювання вологості. +'''Enter a percentage to adjust the humidity.'''.vi=Nhập phần trăm để hiệu chỉnh độ ẩm. +'''Humidity offset'''.en=Humidity offset +'''Humidity offset'''.en-gb=Humidity offset +'''Humidity offset'''.en-us=Humidity offset +'''Humidity offset'''.en-ca=Humidity offset +'''Humidity offset'''.sq=Shmangia në lagështi +'''Humidity offset'''.ar=تعويض الرطوبة +'''Humidity offset'''.be=Карэкцыя вільготнасці +'''Humidity offset'''.sr-ba=Kompenzacija vlage +'''Humidity offset'''.bg=Компенсация на влажността +'''Humidity offset'''.ca=Compensació d'humitat +'''Humidity offset'''.zh-cn=湿度偏差 +'''Humidity offset'''.zh-hk=濕度偏差 +'''Humidity offset'''.zh-tw=濕度偏差 +'''Humidity offset'''.hr=Kompenzacija vlage +'''Humidity offset'''.cs=Posun vlhkosti +'''Humidity offset'''.da=Fugtighedsforskydning +'''Humidity offset'''.nl=Vochtigheidsverschil +'''Humidity offset'''.et=Niiskuse nihkeväärtus +'''Humidity offset'''.fi=Ilmankosteuden siirtymä +'''Humidity offset'''.fr=Compensation de l'humidité +'''Humidity offset'''.fr-ca=Compensation de l'humidité +'''Humidity offset'''.de=Luftfeuchtigkeitsabweichung +'''Humidity offset'''.el=Αντιστάθμιση υγρασίας +'''Humidity offset'''.iw=קיזוז לחות +'''Humidity offset'''.hi-in=नमी की भरपाई +'''Humidity offset'''.hu=Páratartalom-érték eltolása +'''Humidity offset'''.is=Vikmörk raka +'''Humidity offset'''.in=Offset kelembapan +'''Humidity offset'''.it=Differenza umidità +'''Humidity offset'''.ja=湿度オフセット +'''Humidity offset'''.ko=습도 오프셋 +'''Humidity offset'''.lv=Mitruma nobīde +'''Humidity offset'''.lt=Drėgnumo skirtumas +'''Humidity offset'''.ms=Ofset kelembapan +'''Humidity offset'''.no=Fuktighetsforskyvning +'''Humidity offset'''.pl=Różnica wilgotności +'''Humidity offset'''.pt=Diferença de humidade +'''Humidity offset'''.ro=Decalaj umiditate +'''Humidity offset'''.ru=Поправка влажности +'''Humidity offset'''.sr=Odstupanje vlažnosti +'''Humidity offset'''.sk=Posun vlhkosti +'''Humidity offset'''.sl=Odmik vlažnosti +'''Humidity offset'''.es=Compensación de humedad +'''Humidity offset'''.sv=Luftfuktighetsavvikelse +'''Humidity offset'''.th=การชดเชยความชื้น +'''Humidity offset'''.tr=Nem ofseti +'''Humidity offset'''.uk=Поправка вологості +'''Humidity offset'''.vi=Độ lệch độ ẩm +# End of Device Preferences diff --git a/devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/zigbee-motion-temp-humidity-sensor.groovy b/devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/zigbee-motion-temp-humidity-sensor.groovy index 0fa984d012b..11d6e967b64 100644 --- a/devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/zigbee-motion-temp-humidity-sensor.groovy +++ b/devicetypes/smartthings/zigbee-motion-temp-humidity-sensor.src/zigbee-motion-temp-humidity-sensor.groovy @@ -27,7 +27,7 @@ metadata { capability "Health Check" capability "Sensor" - fingerprint inClusters: "0000,0001,0003,0020,0402,0405,0500,0B05,FC01,FC02", outClusters: "0019,0003", manufacturer: "iMagic by GreatStar", model: "1117-S", deviceJoinName: "Iris Motion Sensor" + fingerprint inClusters: "0000,0001,0003,0020,0402,0405,0500,0B05,FC01,FC02", outClusters: "0019,0003", manufacturer: "iMagic by GreatStar", model: "1117-S", deviceJoinName: "Iris Multipurpose Sensor" //Iris Motion Sensor } simulator { @@ -44,8 +44,8 @@ metadata { ]) } section { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false - input "humidityOffset", "number", title: "Humidity Offset", description: "Adjust humidity by this percentage", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false + input "humidityOffset", "number", title: "Humidity offset", description: "Enter a percentage to adjust the humidity.", range: "*..*", displayDuringSetup: false } } @@ -113,7 +113,7 @@ def parse(String description) { if (battMap) { map = getBatteryResult(Integer.parseInt(battMap.value, 16)) } - } else if (descMap?.clusterInt == 0x0500 && descMap.attrInt == 0x0002) { + } else if (descMap?.clusterInt == 0x0500 && descMap.attrInt == 0x0002 && descMap.commandInt != 0x07) { def zs = new ZoneStatus(zigbee.convertToInt(descMap.value, 16)) map = translateZoneStatus(zs) } else if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) { @@ -129,7 +129,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? "${device.displayName} temperature was ${map.value}°C" : "${device.displayName} temperature was ${map.value}°F" map.translatable = true @@ -250,4 +250,4 @@ def configure() { zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000, DataType.UINT16, 30, 3600, 100) return refresh() + configCmds -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/zigbee-multi-button.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-multi-button.src/i18n/messages.properties new file mode 100755 index 00000000000..2b1d2539436 --- /dev/null +++ b/devicetypes/smartthings/zigbee-multi-button.src/i18n/messages.properties @@ -0,0 +1,16 @@ +# Copyright 2019 SmartThings +# +# 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. +# Chinese +'''HEIMAN Remote Control'''.zh-cn=海曼情景开关 +'''HEIMAN Scene Keypad'''.zh-cn=海曼情景开关 diff --git a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy index 2a365408a9c..317bab3c551 100644 --- a/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy +++ b/devicetypes/smartthings/zigbee-multi-button.src/zigbee-multi-button.groovy @@ -18,7 +18,7 @@ import groovy.json.JsonOutput import physicalgraph.zigbee.zcl.DataType metadata { - definition (name: "Zigbee Multi Button", namespace: "smartthings", author: "SmartThings", mcdSync: true) { + definition (name: "Zigbee Multi Button", namespace: "smartthings", author: "SmartThings", mcdSync: true, ocfDeviceType: "x.com.st.d.remotecontroller") { capability "Actuator" capability "Battery" capability "Button" @@ -28,8 +28,15 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L", deviceJoinName: "Iris KeyFob", mnmn: "SmartThings", vid: "generic-4-button" - fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L2", deviceJoinName: "Iris KeyFob", mnmn: "SmartThings", vid: "generic-4-button" + fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L", deviceJoinName: "Iris Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Iris KeyFob + fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L2", deviceJoinName: "Iris Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Iris KeyFob + fingerprint profileId: "0104", inClusters: "0004", outClusters: "0000, 0001, 0003, 0004, 0005, 0B05", manufacturer: "HEIMAN", model: "SceneSwitch-EM-3.0", deviceJoinName: "HEIMAN Remote Control", vid: "generic-4-button" //HEIMAN Scene Keypad + + //AduroSmart + fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FCCC, 1000", outClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FCCC, 1000", manufacturer: "AduroSmart Eria", model: "ADUROLIGHT_CSC", deviceJoinName: "Eria Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Eria scene button switch V2.1 + fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FCCC, 1000", outClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FCCC, 1000", manufacturer: "ADUROLIGHT", model: "ADUROLIGHT_CSC", deviceJoinName: "Eria Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Eria scene button switch V2.0 + fingerprint inClusters: "0000, 0003, 0008, FCCC, 1000", outClusters: "0003, 0004, 0006, 0008, FCCC, 1000", manufacturer: "AduroSmart Eria", model: "Adurolight_NCC", deviceJoinName: "Eria Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Eria dimming button switch V2.1 + fingerprint inClusters: "0000, 0003, 0008, FCCC, 1000", outClusters: "0003, 0004, 0006, 0008, FCCC, 1000", manufacturer: "ADUROLIGHT", model: "Adurolight_NCC", deviceJoinName: "Eria Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //Eria dimming button switch V2.0 } tiles { @@ -65,9 +72,19 @@ def parseAttrMessage(description) { def map = [:] if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap?.value) { map = getBatteryPercentageResult(Integer.parseInt(descMap.value, 16)) - } else if (descMap?.clusterInt == zigbee.ONOFF_CLUSTER && descMap.isClusterSpecific) { + } else if (isAduroSmartRemote()) { + map = parseAduroSmartButtonMessage(descMap) + } else if (descMap?.clusterInt == zigbee.ONOFF_CLUSTER && descMap.isClusterSpecific) { map = getButtonEvent(descMap) - } + } else if (descMap?.clusterInt == 0x0005) { + def buttonNumber + buttonNumber = buttonMap[device.getDataValue("model")][descMap.data[2]] + + log.debug "Number is ${buttonNumber}" + def descriptionText = getButtonName() + " ${buttonNumber} was pushed" + sendEventToChild(buttonNumber, createEvent(name: "button", value: "pushed", data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true)) + map = createEvent(name: "button", value: "pushed", data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true) + } map } @@ -89,7 +106,7 @@ def getButtonResult(buttonState, buttonNumber = 1) { return event } else { buttonState = timeDiff < holdTime ? "pushed" : "held" - def descriptionText = (device.displayName.endsWith(' 1') ? "${device.displayName[0..-2]} button" : "${device.displayName}") + " ${buttonNumber} was ${buttonState}" + def descriptionText = getButtonName() + " ${buttonNumber} was ${buttonState}" event = createEvent(name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true) sendEventToChild(buttonNumber, event) return createEvent(descriptionText: descriptionText) @@ -137,15 +154,20 @@ def ping() { def configure() { def bindings = getModelBindings(device.getDataValue("model")) - return zigbee.onOffConfig() + + def cmds = zigbee.onOffConfig() + zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, batteryVoltage, DataType.UINT8, 30, 21600, 0x01) + zigbee.enrollResponse() + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, batteryVoltage) + bindings + if (isHeimanButton()) + cmds += zigbee.writeAttribute(0x0000, 0x0012, DataType.BOOLEAN, 0x01) + + addHubToGroup(0x000F) + addHubToGroup(0x0010) + addHubToGroup(0x0011) + addHubToGroup(0x0012) + return cmds } def installed() { sendEvent(name: "button", value: "pushed", isStateChange: true, displayed: false) sendEvent(name: "supportedButtonValues", value: supportedButtonValues.encodeAsJSON(), displayed: false) + initialize() } @@ -157,6 +179,7 @@ def initialize() { def numberOfButtons = modelNumberOfButtons[device.getDataValue("model")] sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false) sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) + if(!childDevices) { addChildButtons(numberOfButtons) } @@ -173,7 +196,11 @@ private addChildButtons(numberOfButtons) { for(def endpoint : 1..numberOfButtons) { try { String childDni = "${device.deviceNetworkId}:$endpoint" - def componentLabel = (device.displayName.endsWith(' 1') ? device.displayName[0..-2] : device.displayName) + "${endpoint}" + def componentLabel = getButtonName() + "${endpoint}" + + if (isAduroSmartRemote()) { + componentLabel = device.displayName + " - ${endpoint}" + } def child = addChildDevice("Child Button", childDni, device.getHub().getId(), [ completedSetup: true, label : componentLabel, @@ -203,17 +230,33 @@ private getButtonMap() {[ "02" : 3, "03" : 1, "04" : 2 + ], + "SceneSwitch-EM-3.0" : [ + "01" : 1, + "02" : 2, + "03" : 3, + "04" : 4 ] ]} private getSupportedButtonValues() { - def values = ["pushed", "held"] + def values + if (device.getDataValue("model") == "SceneSwitch-EM-3.0") { + values = ["pushed"] + } else if (isAduroSmartRemote()) { + values = ["pushed"] + } else { + values = ["pushed", "held"] + } return values } private getModelNumberOfButtons() {[ "3450-L" : 4, - "3450-L2" : 4 + "3450-L2" : 4, + "SceneSwitch-EM-3.0" : 4, + "ADUROLIGHT_CSC" : 4, + "Adurolight_NCC" : 4 ]} private getModelBindings(model) { @@ -221,5 +264,57 @@ private getModelBindings(model) { for(def endpoint : 1..modelNumberOfButtons[model]) { bindings += zigbee.addBinding(zigbee.ONOFF_CLUSTER, ["destEndpoint" : endpoint]) } + if (isAduroSmartRemote()) { + bindings += zigbee.addBinding(zigbee.LEVEL_CONTROL_CLUSTER, ["destEndpoint" : 2]) + + zigbee.addBinding(zigbee.LEVEL_CONTROL_CLUSTER, ["destEndpoint" : 3]) + } bindings } + +private getButtonName() { + def values = device.displayName.endsWith(' 1') ? "${device.displayName[0..-2]}" : "${device.displayName}" + return values +} + +private Map parseAduroSmartButtonMessage(Map descMap){ + def buttonState = "pushed" + def buttonNumber = 0 + if (descMap.clusterInt == zigbee.ONOFF_CLUSTER) { + if (descMap.command == "01") { + buttonNumber = 1 + } else if (descMap.command == "00") { + buttonNumber = 4 + } + } else if (descMap.clusterInt == ADUROSMART_SPECIFIC_CLUSTER) { + def list2 = descMap.data + buttonNumber = (list2[1] as int) + 1 + } + if (buttonNumber != 0) { + def childevent = createEvent(name: "button", value: "pushed", data: [buttonNumber: 1], isStateChange: true) + sendEventToChild(buttonNumber, childevent) + def descriptionText = "$device.displayName button $buttonNumber was $buttonState" + return createEvent(name: "button", value: buttonState, data: [buttonNumber: buttonNumber], descriptionText: descriptionText, isStateChange: true) + } else { + return [:] + } +} + +def isAduroSmartRemote(){ + ((device.getDataValue("model") == "Adurolight_NCC") || (device.getDataValue("model") == "ADUROLIGHT_CSC")) +} + +def getADUROSMART_SPECIFIC_CLUSTER() {0xFCCC} + +private getCLUSTER_GROUPS() { 0x0004 } + +private List addHubToGroup(Integer groupAddr) { + ["st cmd 0x0000 0x01 ${CLUSTER_GROUPS} 0x00 {${zigbee.swapEndianHex(zigbee.convertToHexString(groupAddr,4))} 00}", + "delay 200"] +} + +def isHeimanButton(){ + device.getDataValue("model") == "SceneSwitch-EM-3.0" +} + + + diff --git a/devicetypes/smartthings/zigbee-multi-switch-power.src/zigbee-multi-switch-power.groovy b/devicetypes/smartthings/zigbee-multi-switch-power.src/zigbee-multi-switch-power.groovy index efe95f265c1..0cfa8179184 100644 --- a/devicetypes/smartthings/zigbee-multi-switch-power.src/zigbee-multi-switch-power.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch-power.src/zigbee-multi-switch-power.groovy @@ -26,7 +26,7 @@ metadata { command "childOn", ["string"] command "childOff", ["string"] - fingerprint manufacturer: "Aurora", model: "DoubleSocket50AU", deviceJoinName: "AURORA SMART DOUBLE SOCKET 1" //profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04", outClusters: "0019" + fingerprint manufacturer: "Aurora", model: "DoubleSocket50AU", deviceJoinName: "AURORA Outlet 1" //profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04", outClusters: "0019" //AURORA SMART DOUBLE SOCKET 1 } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-multi-switch.src/i18n/messages.properties old mode 100755 new mode 100644 index d8b911964a4..b33d03ae9f0 --- a/devicetypes/smartthings/zigbee-multi-switch.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-multi-switch.src/i18n/messages.properties @@ -13,9 +13,15 @@ # under the License. # Chinese +'''Orvibo Switch 1'''.zh-cn=欧瑞博智能多路墙面开关 1 '''Orvibo 2 Gang Switch 1'''.zh-cn=欧瑞博智能墙面开关(二开) 1 '''Orvibo 3 Gang Switch 1'''.zh-cn=欧瑞博智能墙面开关(三开) 1 +'''GDKES Switch 1'''.zh-cn=粤奇胜智能多路墙面开关 1 '''GDKES 3 Gang Switch 1'''.zh-cn=粤奇胜智能墙面开关(三开) 1 '''GDKES 2 Gang Switch 1'''.zh-cn=粤奇胜智能墙面开关(二开) 1 +'''HONYAR Switch 1'''.zh-cn=鸿雁智能多路墙面开关 1 '''HONYAR 2 Gang Switch 1'''.zh-cn=鸿雁智能墙面开关(二开) 1 '''HONYAR 3 Gang Switch 1'''.zh-cn=鸿雁智能墙面开关(三开) 1 +'''HEIMAN Switch 1'''.zh-cn=海曼智能多路墙面开关 1 +'''HEIMAN 3 Gang Switch 1'''.zh-cn=海曼智能墙面开关(三开) 1 +'''HEIMAN 2 Gang Switch 1'''.zh-cn=海曼智能墙面开关(二开) 1 diff --git a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy old mode 100755 new mode 100644 index 46d215d5bd5..e192b1ef805 --- a/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy +++ b/devicetypes/smartthings/zigbee-multi-switch.src/zigbee-multi-switch.groovy @@ -27,12 +27,39 @@ metadata { command "childOn", ["string"] command "childOff", ["string"] - fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "074b3ffba5a045b7afd94c47079dd553", deviceJoinName: "Orvibo 2 Gang Switch 1" - fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "9f76c9f31b4c4a499e3aca0977ac4494", deviceJoinName: "Orvibo 3 Gang Switch 1" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0005, 0004, 0006", manufacturer: "REXENSE", model: "HY0003", deviceJoinName: "GDKES 3 Gang Switch 1" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0005, 0004, 0006", manufacturer: "REXENSE", model: "HY0002", deviceJoinName: "GDKES 2 Gang Switch 1" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0097", deviceJoinName: "HONYAR 3 Gang Switch 1" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0096", deviceJoinName: "HONYAR 2 Gang Switch 1" + // EZEX + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR2N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR3N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR4N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR5N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR6N0Z0-HA", deviceJoinName: "eZEX Switch 1" //EZEX Switch 1 + + fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "074b3ffba5a045b7afd94c47079dd553", deviceJoinName: "Orvibo Switch 1" //Orvibo 2 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "9f76c9f31b4c4a499e3aca0977ac4494", deviceJoinName: "Orvibo Switch 1" //Orvibo 3 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0005, 0004, 0006", manufacturer: "REXENSE", model: "HY0003", deviceJoinName: "GDKES Switch 1" //GDKES 3 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0005, 0004, 0006", manufacturer: "REXENSE", model: "HY0002", deviceJoinName: "GDKES Switch 1" //GDKES 2 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0097", deviceJoinName: "HONYAR Switch 1" //HONYAR 3 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0096", deviceJoinName: "HONYAR Switch 1" //HONYAR 2 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS2SW3L-EFR-3.0", deviceJoinName: "HEIMAN Switch 1" //HEIMAN 3 Gang Switch 1 + fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS2SW2L-EFR-3.0", deviceJoinName: "HEIMAN Switch 1" //HEIMAN 2 Gang Switch 1 + + // Dawon + fingerprint profileId: "0104", inClusters: "0000, 0002, 0004, 0003, 0006, 0009, 0019", manufacturer: "DAWON_DNS", model: "PM-S240-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch PM-S240-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002, 0004, 0003, 0006, 0009, 0019", manufacturer: "DAWON_DNS", model: "PM-S240R-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch PM-S240R-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002, 0004, 0003, 0006, 0009, 0019", manufacturer: "DAWON_DNS", model: "PM-S340-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch PM-S340-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002, 0004, 0003, 0006, 0009, 0019", manufacturer: "DAWON_DNS", model: "PM-S340R-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch PM-S340R-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002,0003, 0006", manufacturer: "DAWON_DNS", model: "PM-S250-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch PM-S250-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002,0003, 0006", manufacturer: "DAWON_DNS", model: "PM-S350-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch PM-S350-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002,0003, 0006", manufacturer: "DAWON_DNS", model: "ST-S250-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch ST-S250-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002,0003, 0006", manufacturer: "DAWON_DNS", model: "ST-S350-ZB", deviceJoinName: "Dawon Switch 1" //DAWOS DNS In-Wall Switch ST-S350-ZB + + // eWeLink + // Raw Description 01 0104 0100 00 05 0000 0003 0004 0005 0006 01 0000 + fingerprint manufacturer: "eWeLink", model: "ZB-SW02", deviceJoinName: "eWeLink Switch" //eWeLink 2 Gang Switch 1 + // Raw Description 01 0104 0100 00 05 0000 0003 0004 0005 0006 01 0000 + fingerprint manufacturer: "eWeLink", model: "ZB-SW03", deviceJoinName: "eWeLink Switch" //eWeLink 3 Gang Switch 1 + // Raw Description 01 0104 0100 00 05 0000 0003 0004 0005 0006 01 0000 + fingerprint manufacturer: "eWeLink", model: "ZB-SW04", deviceJoinName: "eWeLink Switch" //eWeLink 4 Gang Switch 1 } // simulator metadata simulator { @@ -63,50 +90,52 @@ metadata { } def installed() { - createChildDevices() - updateDataValue("onOff", "catchall") - refresh() + createChildDevices() + updateDataValue("onOff", "catchall") + refresh() } def updated() { - log.debug "updated()" - updateDataValue("onOff", "catchall") - refresh() + log.debug "updated()" + updateDataValue("onOff", "catchall") + for (child in childDevices) { + if (!child.deviceNetworkId.startsWith(device.deviceNetworkId) || //parent DNI has changed after rejoin + !child.deviceNetworkId.split(':')[-1].startsWith('0')) { + child.setDeviceNetworkId("${device.deviceNetworkId}:0${getChildEndpoint(child.deviceNetworkId)}") + } + } + refresh() } def parse(String description) { Map eventMap = zigbee.getEvent(description) Map eventDescMap = zigbee.parseDescriptionAsMap(description) - if (!eventMap && eventDescMap) { - eventMap = [:] - if (eventDescMap?.clusterId == zigbee.ONOFF_CLUSTER) { - eventMap[name] = "switch" - eventMap[value] = eventDescMap?.value - } - } - if (eventMap) { - if (eventDescMap?.sourceEndpoint == "01" || eventDescMap?.endpoint == "01") { - sendEvent(eventMap) - } else { - def childDevice = childDevices.find { - it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.sourceEndpoint}" || it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.endpoint}" - } - if (childDevice) { - childDevice.sendEvent(eventMap) + if (eventDescMap && eventDescMap?.attrId == "0000") {//0x0000 : OnOff attributeId + if (eventDescMap?.sourceEndpoint == "01" || eventDescMap?.endpoint == "01") { + sendEvent(eventMap) } else { - log.debug "Child device: $device.deviceNetworkId:${eventDescMap.sourceEndpoint} was not found" + def childDevice = childDevices.find { + it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.sourceEndpoint}" || it.deviceNetworkId == "$device.deviceNetworkId:${eventDescMap.endpoint}" + } + if (childDevice) { + childDevice.sendEvent(eventMap) + } else { + log.debug "Child device: $device.deviceNetworkId:${eventDescMap.sourceEndpoint} was not found" + } } } } } private void createChildDevices() { - def x = getChildCount() - for (i in 2..x) { - addChildDevice("Child Switch Health", "${device.deviceNetworkId}:0${i}", device.hubId, - [completedSetup: true, label: "${device.displayName[0..-2]}${i}", isComponent: false]) + if (!childDevices) { + def x = getChildCount() + for (i in 2..x) { + addChildDevice("Child Switch Health", "${device.deviceNetworkId}:0${i}", device.hubId, + [completedSetup: true, label: "${device.displayName[0..-2]}${i}", isComponent: false]) + } } } @@ -147,12 +176,12 @@ def refresh() { if (isOrvibo()) { zigbee.readAttribute(zigbee.ONOFF_CLUSTER, 0x0000, [destEndpoint: 0xFF]) } else { - def cmds = zigbee.onOffRefresh() - def x = getChildCount() - for (i in 2..x) { - cmds += zigbee.readAttribute(zigbee.ONOFF_CLUSTER, 0x0000, [destEndpoint: i]) - } - return cmds + def cmds = zigbee.onOffRefresh() + def x = getChildCount() + for (i in 2..x) { + cmds += zigbee.readAttribute(zigbee.ONOFF_CLUSTER, 0x0000, [destEndpoint: i]) + } + return cmds } } @@ -189,17 +218,17 @@ def configure() { if (isOrvibo()) { //the orvibo switch will send out device anounce message at ervery 2 mins as heart beat,setting 0x0099 to 1 will disable it. def cmds = zigbee.writeAttribute(zigbee.BASIC_CLUSTER, 0x0099, 0x20, 0x01, [mfgCode: 0x0000]) - cmds += refresh() - return cmds + cmds += refresh() + return cmds } else { //other devices supported by this DTH in the future - def cmds = zigbee.onOffConfig(0, 120) - def x = getChildCount() - for (i in 2..x) { - cmds += zigbee.configureReporting(zigbee.ONOFF_CLUSTER, 0x0000, 0x10, 0, 120, null, [destEndpoint: i]) - } - cmds += refresh() - return cmds + def cmds = zigbee.onOffConfig(0, 120) + def x = getChildCount() + for (i in 2..x) { + cmds += zigbee.configureReporting(zigbee.ONOFF_CLUSTER, 0x0000, 0x10, 0, 120, null, [destEndpoint: i]) + } + cmds += refresh() + return cmds } } @@ -208,7 +237,19 @@ private Boolean isOrvibo() { } private getChildCount() { - if (device.getDataValue("model") == "9f76c9f31b4c4a499e3aca0977ac4494" || device.getDataValue("model") == "HY0003" || device.getDataValue("model") == "HY0097") { + if (device.getDataValue("model") == "9f76c9f31b4c4a499e3aca0977ac4494" || device.getDataValue("model") == "HY0003" || device.getDataValue("model") == "HY0097" || device.getDataValue("model") == "HS2SW3L-EFR-3.0" ) { + return 3 + } else if (device.getDataValue("model") == "E220-KR2N0Z0-HA") { + return 2 + } else if (device.getDataValue("model") == "E220-KR3N0Z0-HA" || device.getDataValue("model") == "ZB-SW03") { + return 3 + } else if (device.getDataValue("model") == "E220-KR4N0Z0-HA" || device.getDataValue("model") == "ZB-SW04") { + return 4 + } else if (device.getDataValue("model") == "E220-KR5N0Z0-HA") { + return 5 + } else if (device.getDataValue("model") == "E220-KR6N0Z0-HA") { + return 6 + } else if (device.getDataValue("model") == "PM-S340-ZB" || device.getDataValue("model") == "PM-S340R-ZB" || device.getDataValue("model") == "PM-S350-ZB" || device.getDataValue("model") == "ST-S350-ZB") { return 3 } else { return 2 diff --git a/devicetypes/smartthings/zigbee-non-holdable-button.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-non-holdable-button.src/i18n/messages.properties new file mode 100755 index 00000000000..a3cffda3b7f --- /dev/null +++ b/devicetypes/smartthings/zigbee-non-holdable-button.src/i18n/messages.properties @@ -0,0 +1,17 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Button'''.zh-cn=海曼智能紧急按钮 +'''HEIMAN Emergency Button'''.zh-cn=海曼智能紧急按钮 diff --git a/devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy b/devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy new file mode 100755 index 00000000000..45972f054b1 --- /dev/null +++ b/devicetypes/smartthings/zigbee-non-holdable-button.src/zigbee-non-holdable-button.groovy @@ -0,0 +1,196 @@ +/* + * Copyright 2016 SmartThings + * + * 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. + */ +import physicalgraph.zigbee.clusters.iaszone.ZoneStatus +import physicalgraph.zigbee.zcl.DataType + +metadata { + definition(name: "Zigbee Non-Holdable Button", namespace: "smartthings", author: "SmartThings", runLocally: false, mnmn: "SmartThings", vid: "generic-button-2", ocfDeviceType: "x.com.st.d.remotecontroller") { + capability "Configuration" + capability "Battery" + capability "Refresh" + capability "Button" + capability "Health Check" + capability "Sensor" + + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0500", outClusters: "0019", manufacturer: "HEIMAN", model: "SOS-EM", deviceJoinName: "HEIMAN Button" //HEIMAN Emergency Button + } + + tiles(scale: 2) { + multiAttributeTile(name: "button", type: "generic", width: 6, height: 4) { + tileAttribute("device.button", key: "PRIMARY_CONTROL") { + attributeState "pushed", label: "Pressed", icon:"st.Weather.weather14", backgroundColor:"#53a7c0" + } + } + valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) { + state "battery", label: '${currentValue}% battery', unit: "" + } + standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", action: "refresh.refresh", icon: "st.secondary.refresh" + } + + main(["button"]) + details(["button", "battery", "refresh"]) + } +} + +def installed() { + sendEvent(name: "supportedButtonValues", value: ["pushed"].encodeAsJSON(), displayed: false) + sendEvent(name: "numberOfButtons", value: 1, displayed: false) +} + +private List collectAttributes(Map descMap) { + List descMaps = new ArrayList() + + descMaps.add(descMap) + + if (descMap.additionalAttrs) { + descMaps.addAll(descMap.additionalAttrs) + } + + return descMaps +} + +def parse(String description) { + log.debug "description: $description" + + Map map = zigbee.getEvent(description) + if (!map) { + if (description?.startsWith('zone status')) { + map = parseIasMessage(description) + } else { + Map descMap = zigbee.parseDescriptionAsMap(description) + + if (descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && descMap.commandInt != 0x07 && descMap.value) { + List descMaps = collectAttributes(descMap) + def battMap = descMaps.find { it.attrInt == 0x0020 } + + if (battMap) { + map = getBatteryResult(Integer.parseInt(battMap.value, 16)) + } + + } else if (descMap?.clusterInt == 0x0500 && descMap.attrInt == 0x0002) { + def zs = new ZoneStatus(zigbee.convertToInt(descMap.value, 16)) + map = translateZoneStatus(zs) + } else if (descMap?.clusterInt == zigbee.IAS_ZONE_CLUSTER && descMap.attrInt == zigbee.ATTRIBUTE_IAS_ZONE_STATUS && descMap?.value) { + map = translateZoneStatus(new ZoneStatus(zigbee.convertToInt(descMap?.value))) + } + } + } + + log.debug "Parse returned $map" + def result = map ? createEvent(map) : [:] + + if (description?.startsWith('enroll request')) { + List cmds = zigbee.enrollResponse() + log.debug "enroll response: ${cmds}" + result = cmds?.collect { new physicalgraph.device.HubAction(it) } + } + return result +} + +private Map parseIasMessage(String description) { + ZoneStatus zs = zigbee.parseZoneStatus(description) + + translateZoneStatus(zs) +} + +private Map translateZoneStatus(ZoneStatus zs) { + if (zs.isAlarm1Set()) { + return getButtonResult('pushed') + } +} + +private Map getBatteryResult(rawValue) { + log.debug "Battery rawValue = ${rawValue}" + def linkText = getLinkText(device) + + def result = [:] + + def volts = rawValue / 10 + + if (!(rawValue == 0 || rawValue == 255)) { + result.name = 'battery' + result.translatable = true + result.descriptionText = "${ device.displayName } battery was ${ value }%" + + def minVolts = 2.1 + def maxVolts = 3.0 + def pct = (volts - minVolts) / (maxVolts - minVolts) + def roundedPct = Math.round(pct * 100) + if (roundedPct <= 0) + roundedPct = 1 + result.value = Math.min(100, roundedPct) + } + + return result +} + +private Map getBatteryPercentageResult(rawValue) { + log.debug "Battery Percentage rawValue = ${rawValue} -> ${rawValue / 2}%" + def result = [:] + + if (0 <= rawValue && rawValue <= 200) { + result.name = 'battery' + result.translatable = true + result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" + result.value = Math.round(rawValue / 2) + } + + return result +} + +private Map getButtonResult(value) { + def descriptionText + if (value == "pushed") + descriptionText = "${ device.displayName } was pushed" + + return [ + name : 'button', + value : value, + descriptionText: descriptionText, + translatable : true, + isStateChange : true, + data : [buttonNumber: 1] + ] +} + +/** + * PING is used by Device-Watch in attempt to reach the Device + * */ +def ping() { + zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) +} + +def refresh() { + log.debug "Refreshing Values" + def refreshCmds = [] + + refreshCmds += zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + + zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) + + zigbee.enrollResponse() + return refreshCmds +} + +def configure() { + // Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time) + // enrolls with default periodic reporting until newer 5 min interval is confirmed + // Sets up low battery threshold reporting + sendEvent(name: "DeviceWatch-Enroll", displayed: false, value: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, scheme: "TRACKED", checkInterval: 6 * 60 * 60 + 1 * 60, offlinePingable: "1"].encodeAsJSON()) + + return zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + + zigbee.enrollResponse() + + zigbee.batteryConfig() +} diff --git a/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/i18n/messages.properties index 4b53b84c66f..a15dae18a94 100755 --- a/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/i18n/messages.properties @@ -13,5 +13,6 @@ # under the License. # Korean (ko) # Device Preferences +'''eZEX Motion Sensor'''.ko=스마트 재실센서 '''Smart Occupancy Sensor (AC Type)'''.ko=스마트 재실센서 #============================================================================== diff --git a/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/zigbee-plugin-motion-sensor.groovy b/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/zigbee-plugin-motion-sensor.groovy index 56aa7860807..d4186cf2134 100755 --- a/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/zigbee-plugin-motion-sensor.groovy +++ b/devicetypes/smartthings/zigbee-plugin-motion-sensor.src/zigbee-plugin-motion-sensor.groovy @@ -23,7 +23,7 @@ metadata { capability "Health Check" capability "Sensor" - fingerprint profileId: "0104", deviceId: "0107", inClusters: "0000, 0003, 0004, 0406", outClusters: "0006, 0019", model: "E280-KR0A0Z0-HA", deviceJoinName: "Smart Occupancy Sensor (AC Type)" + fingerprint profileId: "0104", deviceId: "0107", inClusters: "0000, 0003, 0004, 0406", outClusters: "0006, 0019", model: "E280-KR0A0Z0-HA", deviceJoinName: "eZEX Motion Sensor" //Smart Occupancy Sensor (AC Type) } tiles(scale: 2) { multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) { diff --git a/devicetypes/smartthings/zigbee-power-meter.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-power-meter.src/i18n/messages.properties index 08f262c6544..4e048035bb5 100755 --- a/devicetypes/smartthings/zigbee-power-meter.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-power-meter.src/i18n/messages.properties @@ -13,5 +13,6 @@ # under the License. # Korean (ko) # Device Preferences +'''Energy Monitor'''.ko=스마트 에너지미터(CT형) '''Smart Sub-meter(CT Type)'''.ko=스마트 에너지미터(CT형) #============================================================================== diff --git a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy index 91d9296caff..99b9b56c318 100755 --- a/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy +++ b/devicetypes/smartthings/zigbee-power-meter.src/zigbee-power-meter.groovy @@ -12,7 +12,7 @@ * */ metadata { - definition (name: "Zigbee Power Meter", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "SmartThings-smartthings-Aeon_Home_Energy_Meter") { + definition (name: "Zigbee Power Meter", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", ocfDeviceType: "x.com.st.d.energymeter", vid: "SmartThings-smartthings-Aeon_Home_Energy_Meter") { capability "Energy Meter" capability "Power Meter" capability "Refresh" @@ -20,7 +20,7 @@ metadata { capability "Sensor" capability "Configuration" - fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR080Z0-HA", deviceJoinName: "Smart Sub-meter(CT Type)" + fingerprint profileId: "0104", deviceId:"0053", inClusters: "0000, 0003, 0004, 0B04, 0702", outClusters: "0019", manufacturer: "", model: "E240-KR080Z0-HA", deviceJoinName: "Energy Monitor" //Smart Sub-meter(CT Type) } @@ -52,8 +52,15 @@ def parse(String description) { if (event) { log.info event if (event.name == "power") { - event.value = event.value/1000 - event.unit = "W" + def descMap = zigbee.parseDescriptionAsMap(description) + log.debug "event : Desc Map: $descMap" + if (descMap.clusterInt == 0x0B04 && descMap.attrInt == 0x050b) { + event.value = event.value/10 + event.unit = "W" + } else { + event.value = event.value/1000 + event.unit = "W" + } } else if (event.name == "energy") { event.value = event.value/1000000 event.unit = "kWh" @@ -77,6 +84,12 @@ def parse(String description) { map.value = zigbee.convertHexToInt(it.value)/1000 map.unit = "W" } + if (it.clusterInt == 0x0B04 && it.attrInt == 0x050b) { + log.debug "meter" + map.name = "power" + map.value = zigbee.convertHexToInt(it.value)/10 + map.unit = "W" + } if (it.clusterInt == 0x0702 && it.attrInt == 0x0000) { log.debug "energy" map.name = "energy" diff --git a/devicetypes/smartthings/zigbee-range-extender.src/zigbee-range-extender.groovy b/devicetypes/smartthings/zigbee-range-extender.src/zigbee-range-extender.groovy index bbc29342198..3981275654d 100644 --- a/devicetypes/smartthings/zigbee-range-extender.src/zigbee-range-extender.groovy +++ b/devicetypes/smartthings/zigbee-range-extender.src/zigbee-range-extender.groovy @@ -16,8 +16,9 @@ metadata { definition (name: "Zigbee Range Extender", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.networking", mnmn: "SmartThings", vid: "SmartThings-smartthings-Z-Wave_Range_Extender") { capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0009, 0B05, 1000, FC7C", outClusters: "0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI signal repeater", deviceJoinName: "TRÅDFRI Signal Repeater" - fingerprint profileId: "0104", inClusters: "0000, 0003", outClusters: "0019", manufacturer: "Smartenit, Inc", model: "ZB3RE", deviceJoinName: "Smartenit Range Extender" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0009, 0B05, 1000, FC7C", outClusters: "0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI signal repeater", deviceJoinName: "IKEA Repeater/Extender" //TRÅDFRI Signal Repeater + fingerprint profileId: "0104", inClusters: "0000, 0003", outClusters: "0019", manufacturer: "Smartenit, Inc", model: "ZB3RE", deviceJoinName: "Smartenit Repeater/Extender" //Smartenit Range Extender + fingerprint profileId: "0104", inClusters: "0000, 0003, DC00, FC01", manufacturer: "Rooms Beautiful", model: "R001", deviceJoinName: "Rooms Beautiful Repeater/Extender" //Range Extender } tiles(scale: 2) { @@ -58,4 +59,4 @@ def ping() { sendHubCommand(zigbee.readAttribute(zigbee.BASIC_CLUSTER, ZCL_VERSION_ATTRIBUTE)) } -private getZCL_VERSION_ATTRIBUTE() { 0x0000 } \ No newline at end of file +private getZCL_VERSION_ATTRIBUTE() { 0x0000 } diff --git a/devicetypes/smartthings/zigbee-rgb-bulb.src/zigbee-rgb-bulb.groovy b/devicetypes/smartthings/zigbee-rgb-bulb.src/zigbee-rgb-bulb.groovy index 83e9348a04a..a73bab38c43 100644 --- a/devicetypes/smartthings/zigbee-rgb-bulb.src/zigbee-rgb-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgb-bulb.src/zigbee-rgb-bulb.groovy @@ -30,9 +30,9 @@ metadata { capability "Light" // OSRAM/SYLVANIA - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenspot RGB", deviceJoinName: "SYLVANIA Smart Gardenspot mini RGB" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Gardenspot RGB", deviceJoinName: "SYLVANIA Smart Gardenspot mini RGB" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "Outdoor Accent RGB", deviceJoinName: "SYLVANIA Outdoor Accent RGB" + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenspot RGB", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Gardenspot mini RGB + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Gardenspot RGB", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Gardenspot mini RGB + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "Outdoor Accent RGB", deviceJoinName: "SYLVANIA Light" //SYLVANIA Outdoor Accent RGB } // UI tile definitions diff --git a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy index 07dbc910695..24fc4c54c6f 100644 --- a/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zigbee-rgbw-bulb.src/zigbee-rgbw-bulb.groovy @@ -33,53 +33,70 @@ metadata { attribute "colorName", "string" // Generic fingerprint - fingerprint profileId: "0104", deviceId: "0102", inClusters: "0006, 0008, 0300", deviceJoinName: "Generic RGBW Light" - fingerprint profileId: "0104", deviceId: "010D", inClusters: "0006, 0008, 0300", deviceJoinName: "Generic RGBW Light" + fingerprint profileId: "0104", deviceId: "0102", inClusters: "0006, 0008, 0300", deviceJoinName: "Light" //Generic RGBW Light + fingerprint profileId: "0104", deviceId: "010D", inClusters: "0006, 0008, 0300", deviceJoinName: "Light" //Generic RGBW Light // AduroSmart - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010D", manufacturer: "AduroSmart Eria", model: "AD-RGBW3001", deviceJoinName: "Eria ZigBee RGBW Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010D", manufacturer: "AduroSmart Eria", model: "AD-RGBW3001", deviceJoinName: "Eria Light" //Eria ZigBee RGBW Bulb // Aurora/AOne - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Aurora", model: "RGBCXStrip50AU", deviceJoinName: "AOne Smart Strip Controller", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-2500K-6000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: " RGBGU10Bulb50AU", deviceJoinName: "Aurora Smart RGBW" - fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300, FFFF, 1000", outClusters: "0019", manufacturer: "Aurora", model: "RGBBulb51AU", deviceJoinName: "Aurora RGBW GLS Lamp" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FFFF", outClusters: "0019", manufacturer: "Aurora", model: "RGBBulb51AU", deviceJoinName: "AOne Smart RGBW GLS Lamp" - + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Aurora", model: "RGBCXStrip50AU", deviceJoinName: "AOne Light", mnmn:"SmartThings", ocfDeviceType: "oic.d.switch", vid: "generic-rgbw-color-bulb-2500K-6000K" //AOne Smart Strip Controller + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: " RGBGU10Bulb50AU", deviceJoinName: "Aurora Light" //Aurora Smart RGBW + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300, FFFF, 1000", outClusters: "0019", manufacturer: "Aurora", model: "RGBBulb51AU", deviceJoinName: "Aurora Light" //Aurora RGBW GLS Lamp + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FFFF", outClusters: "0019", manufacturer: "Aurora", model: "RGBBulb51AU", deviceJoinName: "AOne Light" //AOne Smart RGBW GLS Lamp + + //CWD + // raw description "01 0104 010D 01 0A 0000 0003 0004 0005 0006 0008 0300 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.A806Ergbw-A001", deviceJoinName: "CWD Light" //model: "E27 RGBW & Colour Tuneable", brand: "Collingwood" + // raw description "01 0104 010D 01 0A 0000 0003 0004 0005 0006 0008 0300 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.A806Brgbw-A001", deviceJoinName: "CWD Light" //model: "BC RGBW & Colour Tuneable", brand: "Collingwood" + // raw description "01 0104 010D 01 0A 0000 0003 0004 0005 0006 0008 0300 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.M350rgbw-A001", deviceJoinName: "CWD Light" //model: "GU10 RGBW & Colour Tuneable", brand: "Collingwood" + // Innr - fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 285 C", deviceJoinName: "Innr Smart Bulb Color" - fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "BY 285 C", deviceJoinName: "Innr Smart Bulb Color" - fingerprint manufacturer: "innr", model: "RB 250 C", deviceJoinName: "Innr Smart Candle Colour", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" - fingerprint manufacturer: "innr", model: "RS 230 C", deviceJoinName: "Innr Smart GU10 Spot Colour", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 285 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Smart Bulb Color + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "BY 285 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Smart Bulb Color + fingerprint manufacturer: "innr", model: "RB 250 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Smart Candle Colour + fingerprint manufacturer: "innr", model: "RS 230 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Smart GU10 Spot Colour + fingerprint manufacturer: "innr", model: "AE 280 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Smart Color Bulb E26 AE 280 C // Müller Licht - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "MLI", model: "ZBT-ExtendedColor", deviceJoinName: "Müller Licht Bulb White+Color", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "MLI", model: "ZBT-ExtendedColor", deviceJoinName: "Tint Light", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Müller Licht Bulb White+Color // LEDVANCE/OSRAM/SYLVANIA - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Flex RGBW", deviceJoinName: "SYLVANIA Smart Flex RGBW" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Flex RGBW", deviceJoinName: "OSRAM SMART+ Flex RGBW" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 RGBW", deviceJoinName: "SYLVANIA Smart A19 RGBW" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR RGBW", deviceJoinName: "SYLVANIA Smart BR30 RGBW" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT RGBW", deviceJoinName: "SYLVANIA Smart RT5/6 RGBW" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY FLEX OUTDOOR RGBW", deviceJoinName: "SYLVANIA Smart RGBW Flex" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "RT HO RGBW", deviceJoinName: "SYLVANIA Smart RT HO RGBW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "A19 RGBW", deviceJoinName: "SYLVANIA Smart A19 RGBW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "FLEX Outdoor RGBW", deviceJoinName: "SYLVANIA Smart Flex RGBW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "FLEX RGBW", deviceJoinName: "SYLVANIA Smart Flex RGBW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "BR30 RGBW", deviceJoinName: "SYLVANIA Smart BR30 RGBW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "RT RGBW", deviceJoinName: "SYLVANIA Smart RT5/6 RGBW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "Outdoor Pathway RGBW", deviceJoinName: "SYLVANIA Outdoor Pathway Full Color" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "Flex RGBW Pro", deviceJoinName: "SYLVANIA Smart Flex 11 RGBW" + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Flex RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Flex RGBW + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Flex RGBW", deviceJoinName: "OSRAM Light" //OSRAM SMART+ Flex RGBW + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart A19 RGBW + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart BR30 RGBW + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart RT5/6 RGBW + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY FLEX OUTDOOR RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart RGBW Flex + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "RT HO RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart RT HO RGBW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "A19 RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart A19 RGBW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "FLEX Outdoor RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Flex RGBW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "FLEX RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Flex RGBW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "BR30 RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart BR30 RGBW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "RT RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart RT5/6 RGBW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "Outdoor Pathway RGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Outdoor Pathway Full Color + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "Flex RGBW Pro", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Flex 11 RGBW // Leedarson/Ozom - fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "LEEDARSON LIGHTING", model: "5ZB-A806ST-Q1G", deviceJoinName: "Ozom Multicolor Smart Light" + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "LEEDARSON LIGHTING", model: "5ZB-A806ST-Q1G", deviceJoinName: "Ozom Light" //Ozom Multicolor Smart Light // Sengled fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0702,0B05,FC03,FC04", outClusters: "0019", manufacturer: "sengled", model: "E11-N1EA", deviceJoinName: "Sengled Multicolor" - fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0702,0B05,FC03,FC04", outClusters: "0019", manufacturer: "sengled", model: "E12-N1E", deviceJoinName: "Sengled Element Color Plus" + fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0702,0B05,FC03,FC04", outClusters: "0019", manufacturer: "sengled", model: "E12-N1E", deviceJoinName: "Sengled Element Color Plus" fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0702,0B05,FC03,FC04", outClusters: "0019", manufacturer: "sengled", model: "E21-N1EA", deviceJoinName: "Sengled Multicolor" fingerprint manufacturer: "sengled", model: "E1G-G8E", deviceJoinName: "Sengled Smart Light Strip", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05, FC03", outClusters: "0019", manufacturer: "sengled", model: "E11-U3E", deviceJoinName: "Sengled Element Color Plus", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05, FC03", outClusters: "0019", manufacturer: "sengled", model: "E11-U2E", deviceJoinName: "Sengled Element Color Plus" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05, FC03, FC04", outClusters: "0019", manufacturer: "sengled", model: "E1F-N5E", deviceJoinName: "Sengled Light" + + // Q Smart Lights + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Neuhaus Lighting Group", model: "ZBT-ExtendedColor", deviceJoinName: "Q-Smart Light", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" + + // Ajax Online + fingerprint manufacturer: "Ajaxonline", model: "AJ-RGBCCT 5 in 1", deviceJoinName: "Ajax Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" + fingerprint manufacturer: "Ajax online Ltd", model: "AJ_ZB30_GU10", deviceJoinName: "Ajax Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" // Raw Description: 0B 0104 010D 01 08 0000 0003 0004 0005 0006 0008 0300 1000 00 } // UI tile definitions @@ -120,7 +137,6 @@ private getHUE_COMMAND() { 0x00 } private getSATURATION_COMMAND() { 0x03 } private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 } private getCOLOR_CONTROL_CLUSTER() { 0x0300 } -private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 } // Parse incoming device messages to generate events def parse(String description) { @@ -188,12 +204,9 @@ def ping() { def refresh() { zigbee.onOffRefresh() + - zigbee.levelRefresh() + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + - zigbee.onOffConfig(0, 300) + - zigbee.levelConfig() + zigbee.levelRefresh() + + zigbee.colorTemperatureRefresh() + + zigbee.hueSaturationRefresh() } def configure() { @@ -202,17 +215,24 @@ def configure() { // enrolls with default periodic reporting until newer 5 min interval is confirmed sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) - // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity - refresh() + + def cmds = [] + if(device.currentState("colorTemperature")?.value == null) { + cmds += zigbee.setColorTemperature(5000) + } + + cmds += refresh() + + // OnOff, level minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity + zigbee.onOffConfig(0, 300) + + zigbee.levelConfig(0, 300) + cmds } def setColorTemperature(value) { value = value as Integer - def tempInMired = Math.round(1000000 / value) - def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4)) - zigbee.command(COLOR_CONTROL_CLUSTER, 0x0A, "$finalHex 0000") + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.setColorTemperature(value) + + zigbee.colorTemperatureRefresh() } //Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature @@ -247,20 +267,19 @@ private getScaledSaturation(value) { def setColor(value){ log.trace "setColor($value)" zigbee.on() + - zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND, - getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND, + getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") + + zigbee.hueSaturationRefresh() } def setHue(value) { zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) } def setSaturation(value) { zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") + - zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) } def installed() { @@ -268,5 +287,11 @@ def installed() { if ((device.currentState("level")?.value == null) || (device.currentState("level")?.value == 0)) { sendEvent(name: "level", value: 100) } + } else if (isTintBulb()) { + sendHubCommand(zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND, getScaledHue(0), getScaledSaturation(0), "0000")) } } + +private boolean isTintBulb() { + device.getDataValue("model") == "ZBT-ExtendedColor" +} diff --git a/devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties new file mode 100644 index 00000000000..9d741777bbf --- /dev/null +++ b/devicetypes/smartthings/zigbee-scene-keypad.src/i18n/messages.properties @@ -0,0 +1,21 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Remote Control'''.zh-cn=海曼情景开关 +'''HEIMAN Scene Keypad'''.zh-cn=海曼情景开关 +'''ORVIBO Remote Control'''.zh-cn=欧瑞博情景开关 +'''ORVIBO Scene Keypad'''.zh-cn=欧瑞博情景开关 +'''GDKES Remote Control'''.zh-cn=粤奇胜情景开关 +'''GDKES Scene Keypad'''.zh-cn=粤奇胜情景开关 diff --git a/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy b/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy index e078e32cca7..2fddefda37e 100644 --- a/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy +++ b/devicetypes/smartthings/zigbee-scene-keypad.src/zigbee-scene-keypad.groovy @@ -18,7 +18,7 @@ import groovy.json.JsonOutput import physicalgraph.zigbee.zcl.DataType metadata { - definition (name: "Zigbee Scene Keypad", namespace: "smartthings", author: "SmartThings", mcdSync: true) { + definition (name: "Zigbee Scene Keypad", namespace: "smartthings", author: "SmartThings", mcdSync: true, ocfDeviceType: "x.com.st.d.remotecontroller") { capability "Actuator" capability "Button" capability "Configuration" @@ -26,9 +26,10 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005", outClusters: "0003, 0004, 0005", manufacturer: "REXENSE", model: "HY0048", deviceJoinName: "情景开关 1", vid: "generic-4-button-alt" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005", outClusters: "0003, 0004, 0005", manufacturer: "REXENSE", model: "0106-G", deviceJoinName: "情景开关 1", vid: "generic-6-button-alt" - fingerprint profileId: "0104", inClusters: "0000, 0005", outClusters: "0000, 0005, 0017", manufacturer: "ORVIBO", model: "cef8701bb8664a67a83033c071ef05f2", deviceJoinName: "情景开关 1", vid: "generic-3-button-alt" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005", outClusters: "0003, 0004, 0005", manufacturer: "REXENSE", model: "HY0048", deviceJoinName: "GDKES Remote Control", vid: "generic-4-button-alt" //GDKES Scene Keypad + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005", outClusters: "0003, 0004, 0005", manufacturer: "REXENSE", model: "0106-G", deviceJoinName: "GDKES Remote Control", vid: "generic-6-button-alt" //GDKES Scene Keypad + fingerprint profileId: "0104", inClusters: "0000, 0005", outClusters: "0000, 0005, 0017", manufacturer: "ORVIBO", model: "cef8701bb8664a67a83033c071ef05f2", deviceJoinName: "ORVIBO Remote Control", vid: "generic-3-button-alt" //ORVIBO Scene Keypad + fingerprint profileId: "0104", inClusters: "0004", outClusters: "0000, 0001, 0003, 0004, 0005, 0B05", manufacturer: "HEIMAN", model: "E-SceneSwitch-EM-3.0", deviceJoinName: "HEIMAN Remote Control", vid: "generic-4-button-alt" //HEIMAN Scene Keypad } @@ -58,13 +59,15 @@ def parse(String description) { def parseAttrMessage(description) { def descMap = zigbee.parseDescriptionAsMap(description) - if (descMap?.clusterInt == 0x0017 || descMap?.clusterInt == 0xFE05) { + if (descMap?.clusterInt == 0x0017 || descMap?.clusterInt == 0xFE05 || descMap?.clusterInt == 0x0005) { def event = [:] def buttonNumber if (descMap?.clusterInt == 0x0017) { - buttonNumber = Integer.valueOf(descMap.data[0]) + buttonNumber = Integer.valueOf(descMap.data[0]) } else if (descMap?.clusterInt == 0xFE05) { - buttonNumber = Integer.valueOf(descMap?.value) + buttonNumber = Integer.valueOf(descMap?.value) + } else if(descMap?.clusterInt == 0x0005) { + buttonNumber = buttonNum[device.getDataValue("model")][descMap.data[2]] } log.debug "Number is ${buttonNumber}" event = createEvent(name: "button", value: "pushed", data: [buttonNumber: buttonNumber], descriptionText: "pushed", isStateChange: true) @@ -91,7 +94,11 @@ def ping() { } def configure() { - return zigbee.enrollResponse() + def cmds = zigbee.enrollResponse() + if (isHeimanButton()) + cmds += zigbee.writeAttribute(0x0000, 0x0012, DataType.BOOLEAN, 0x01) + + addHubToGroup(0x000F) + addHubToGroup(0x0010) + addHubToGroup(0x0011) + addHubToGroup(0x0013) + return cmds } def installed() { @@ -101,7 +108,16 @@ def installed() { if (!childDevices) { addChildButtons(numberOfButtons) } - sendEvent(name: "supportedButtonValues", value: ["pushed"]) + if (childDevices) { + def event + for (def endpoint : 1..device.currentValue("numberOfButtons")) { + event = createEvent(name: "button", value: "pushed", isStateChange: true, displayed: false) + sendEventToChild(endpoint, event) + } + } + + sendEvent(name: "button", value: "pushed", isStateChange: true, displayed: false) + sendEvent(name: "supportedButtonValues", value: supportedButtonValues.encodeAsJSON(), displayed: false) } def updated() { @@ -113,26 +129,55 @@ def initialize() { } private addChildButtons(numberOfButtons) { - for (def i : 2..numberOfButtons) { + for (def endpoint : 2..numberOfButtons) { try { - String childDni = "${device.deviceNetworkId}:$i" - def componentLabel = (device.displayName.endsWith(' 1') ? device.displayName[0..-2] : device.displayName) + "${i}" - addChildDevice("Child Button", "${device.deviceNetworkId}:${i}", device.hubId, - [completedSetup: true, label: "${device.displayName} button ${i}", - isComponent: true, componentName: "button$i", componentLabel: "Button $i"]) - } catch (Exception e) { + String childDni = "${device.deviceNetworkId}:$endpoint" + def childLabel = (device.displayName.endsWith(' 1') ? device.displayName[0..-2] : device.displayName) + "${endpoint}" + def child = addChildDevice("Child Button", childDni, device.getHub().getId(), [ + completedSetup: true, + label : childLabel, + isComponent : true, + componentName : "button$endpoint", + componentLabel: "Button $endpoint" + ]) + child.sendEvent(name: "supportedButtonValues", value: supportedButtonValues.encodeAsJSON(), displayed: false) + } catch(Exception e) { log.debug "Exception: ${e}" } } } +private getSupportedButtonValues() { + def values = ["pushed"] + return values +} + private getChildCount() { if (device.getDataValue("model") == "0106-G") { return 6 - } else if (device.getDataValue("model") == "HY0048") { + } else if (device.getDataValue("model") == "HY0048" || device.getDataValue("model") == "E-SceneSwitch-EM-3.0") { return 4 } else if (device.getDataValue("model") == "cef8701bb8664a67a83033c071ef05f2") { return 3 } } +private getCLUSTER_GROUPS() { 0x0004 } + +private boolean isHeimanButton() { + device.getDataValue("model") == "E-SceneSwitch-EM-3.0" +} + +private List addHubToGroup(Integer groupAddr) { + ["st cmd 0x0000 0x01 ${CLUSTER_GROUPS} 0x00 {${zigbee.swapEndianHex(zigbee.convertToHexString(groupAddr,4))} 00}", + "delay 200"] +} + +private getButtonNum() {[ + "E-SceneSwitch-EM-3.0" : [ + "01" : 2, + "02" : 1, + "03" : 3, + "05" : 4 + ] +]} \ No newline at end of file diff --git a/devicetypes/smartthings/zigbee-smoke-sensor.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-smoke-sensor.src/i18n/messages.properties new file mode 100755 index 00000000000..e5082ea9b65 --- /dev/null +++ b/devicetypes/smartthings/zigbee-smoke-sensor.src/i18n/messages.properties @@ -0,0 +1,18 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Chinese +'''HEIMAN Smoke Sensor (HS1SA-E)'''.zh-cn=海曼烟雾报警器 +'''HEIMAN Smoke Sensor (HS3SA)'''.zh-cn=海曼烟雾报警器(HS3SA) +'''Orvibo Smoke Detector'''.zh-cn=欧瑞博 烟雾报警器(SF21) \ No newline at end of file diff --git a/devicetypes/smartthings/zigbee-smoke-sensor.src/zigbee-smoke-sensor.groovy b/devicetypes/smartthings/zigbee-smoke-sensor.src/zigbee-smoke-sensor.groovy old mode 100644 new mode 100755 index fd55079cc0b..111dfe830ec --- a/devicetypes/smartthings/zigbee-smoke-sensor.src/zigbee-smoke-sensor.groovy +++ b/devicetypes/smartthings/zigbee-smoke-sensor.src/zigbee-smoke-sensor.groovy @@ -28,8 +28,11 @@ metadata { capability "Refresh" capability "Health Check" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0502,0009", outClusters: "0019", manufacturer: "Heiman", model: "b5db59bfd81e4f1f95dc57fdbba17931", deviceJoinName: "欧瑞博 烟雾报警器(SF21)" - fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0502,0009", outClusters: "0019", manufacturer: "HEIMAN", model: "98293058552c49f38ad0748541ee96ba", deviceJoinName: "欧瑞博 烟雾报警器(SF21)" + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0502,0009", outClusters: "0019", manufacturer: "Heiman", model: "b5db59bfd81e4f1f95dc57fdbba17931", deviceJoinName: "Orvibo Smoke Detector" //欧瑞博 烟雾报警器(SF21) + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0502,0009", outClusters: "0019", manufacturer: "HEIMAN", model: "98293058552c49f38ad0748541ee96ba", deviceJoinName: "Orvibo Smoke Detector" //欧瑞博 烟雾报警器(SF21) + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0502", outClusters: "0019", manufacturer: "HEIMAN", model: "SmokeSensor-EM", deviceJoinName: "HEIMAN Smoke Detector" //HEIMAN Smoke Sensor (HS1SA-E) + fingerprint profileId: "0104", deviceId: "0402", inClusters: "0000,0001,0003,0500,0502,0B05", outClusters: "0019", manufacturer: "HEIMAN", model: "SmokeSensor-N-3.0", deviceJoinName: "HEIMAN Smoke Detector" //HEIMAN Smoke Sensor (HS3SA) + } tiles { @@ -141,7 +144,7 @@ def ping() { def configure() { log.debug "configure" - sendEvent(name: "checkInterval", value:10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) + sendEvent(name: "checkInterval", value:20 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) Integer minReportTime = 0 Integer maxReportTime = 180 Integer reportableChange = null diff --git a/devicetypes/smartthings/zigbee-sound-sensor.src/zigbee-sound-sensor.groovy b/devicetypes/smartthings/zigbee-sound-sensor.src/zigbee-sound-sensor.groovy index 61748e47a91..d650f22b940 100644 --- a/devicetypes/smartthings/zigbee-sound-sensor.src/zigbee-sound-sensor.groovy +++ b/devicetypes/smartthings/zigbee-sound-sensor.src/zigbee-sound-sensor.groovy @@ -27,7 +27,7 @@ metadata { capability "Sound Sensor" capability "Temperature Measurement" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Ecolink", model: "FFZB1-SM-ECO", deviceJoinName: "Ecolink Firefighter" + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "Ecolink", model: "FFZB1-SM-ECO", deviceJoinName: "Ecolink Sound Sensor" //Ecolink Firefighter } tiles(scale: 2) { @@ -83,7 +83,7 @@ def parse(String description) { } } else if (map.name == "temperature") { if (tempOffset) { - map.value = (int) map.value + (int) tempOffset + map.value = new BigDecimal((map.value as float) + (tempOffset as float)).setScale(1, BigDecimal.ROUND_HALF_UP) } map.descriptionText = temperatureScale == 'C' ? "${device.displayName} was ${map.value}°C" : "${device.displayName} was ${map.value}°F" map.translatable = true @@ -184,4 +184,4 @@ def configure() { private boolean isZoneMessage(description) { return (description?.startsWith('zone status') || description?.startsWith('zone report')) -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy index 91ef27db772..15563dc1217 100644 --- a/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy +++ b/devicetypes/smartthings/zigbee-switch-power.src/zigbee-switch-power.groovy @@ -24,28 +24,36 @@ metadata { capability "Light" // Generic - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04", deviceJoinName: "Switch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702", deviceJoinName: "Switch" // Aurora - fingerprint profileId: "0104", inClusters: "0000, 0702, 0003, 0009, 0B04, 0006, 0004, 0005, 0002", outClusters: "0000, 0019, 000A, 0003, 0406", manufacturer: "Develco Products A/S", model: "Smart16ARelay51AU", deviceJoinName: "Aurora Smart Inline Relay" - fingerprint profileId: "0104", inClusters: "0000, 0702, 0003, 0009, 0B04, 0006, 0004, 0005, 0002", outClusters: "0000, 0019, 000A, 0003, 0406", manufacturer: "Aurora", model: "Smart16ARelay51AU", deviceJoinName: "Aurora Smart Inline Relay" + fingerprint profileId: "0104", inClusters: "0000, 0702, 0003, 0009, 0B04, 0006, 0004, 0005, 0002", outClusters: "0000, 0019, 000A, 0003, 0406", manufacturer: "Develco Products A/S", model: "Smart16ARelay51AU", deviceJoinName: "Aurora Switch" //Aurora Smart Inline Relay + fingerprint profileId: "0104", inClusters: "0000, 0702, 0003, 0009, 0B04, 0006, 0004, 0005, 0002", outClusters: "0000, 0019, 000A, 0003, 0406", manufacturer: "Aurora", model: "Smart16ARelay51AU", deviceJoinName: "Aurora Switch" //Aurora Smart Inline Relay + + // EZEX + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006, 0B04, 0702", outClusters: "0019", model: "E210-KR210Z1-HA", deviceJoinName: "eZEX Switch" //EZEX Plug // GE/Jasco - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE Outlet", ocfDeviceType: "oic.d.smartplug" //GE ZigBee Plug-In Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE Switch" //GE ZigBee In-Wall Switch // INGENIUM - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04", outClusters: "0000, 0004", manufacturer: "MEGAMAN", model: "SH-PSUKC44B-E", deviceJoinName: "INGENIUM ZB Smart Power Adaptor", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04", outClusters: "0000, 0004", manufacturer: "MEGAMAN", model: "SH-PSUKC44B-E", deviceJoinName: "INGENIUM Outlet", ocfDeviceType: "oic.d.smartplug" //INGENIUM ZB Smart Power Adaptor // Ozom - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "PSM_00.00.00.35TC", deviceJoinName: "Ozom Smart Plug", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702", outClusters: "0000", manufacturer: "ClimaxTechnology", model: "PSM_00.00.00.35TC", deviceJoinName: "Ozom Outlet", ocfDeviceType: "oic.d.smartplug" //Ozom Smart Plug // Philio - fingerprint manufacturer: " ", model: "PAN18-v1.0.7", deviceJoinName: "Philio Smart Plug", ocfDeviceType: "oic.d.smartplug" //profileId: "0104", inClusters: "0000, 0003, 0006, 0702", outClusters: "0003, 0019", + fingerprint manufacturer: " ", model: "PAN18-v1.0.7", deviceJoinName: "Philio Outlet", ocfDeviceType: "oic.d.smartplug" //profileId: "0104", inClusters: "0000, 0003, 0006, 0702", outClusters: "0003, 0019", //Philio Smart Plug // Salus - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702", manufacturer: "SALUS", model: "SX885ZB", deviceJoinName: "Salus miniSmartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702", manufacturer: "SALUS", model: "SX885ZB", deviceJoinName: "Salus Switch" //Salus miniSmartplug + + //AduroSmart + fingerprint profileId: "0104", deviceId: "0051", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 1000, 0702", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "AD-SmartPlug3001", deviceJoinName: "Eria Switch" //Eria Zigbee Smart Plug + fingerprint profileId: "0104", deviceId: "010A", inClusters: "0000, 0003, 0004, 0005, 0006, 1000", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "BPU3", deviceJoinName: "Eria Switch" //Eria Zigbee On/Off Plug + fingerprint profileId: "0104", deviceId: "0101", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "BDP3001", deviceJoinName: "Eria Switch" //Eria Zigbee Dimmable Plug } tiles(scale: 2) { @@ -135,4 +143,4 @@ def updated() { def ping() { return zigbee.onOffRefresh() -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties index b055a9a4b11..7179338dfc1 100755 --- a/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-switch.src/i18n/messages.properties @@ -13,10 +13,19 @@ # under the License. # Chinese +'''Orvibo Switch'''.zh-cn=欧瑞博智能墙面开关(一开) '''Orvibo Smart Switch'''.zh-cn=欧瑞博智能墙面开关(一开) +'''Orvibo Outlet'''.zh-cn=欧瑞博二三极智能插座 '''Orvibo Smart Outlet'''.zh-cn=欧瑞博二三极智能插座 +'''GDKES Switch'''.zh-cn=粤奇胜智能墙面开关(一开) '''GDKES Smart Switch'''.zh-cn=粤奇胜智能墙面开关(一开) +'''GDKES Outlet'''.zh-cn=粤奇胜三极智能插座 '''GDKES Smart Outlet (GDKES-016)'''.zh-cn=粤奇胜三极智能插座 +'''GDKES Outlet'''.zh-cn=粤奇胜二三极智能插座 '''GDKES Smart Outlet (GDKES-015)'''.zh-cn=粤奇胜二三极智能插座 +'''Terncy Switch'''.zh-cn=小燕智能灯座 '''Terncy Smart Light Socket'''.zh-cn=小燕智能灯座 +'''HONYAR Switch'''.zh-cn=鸿雁智能墙面开关(一开) '''HONYAR Smart Switch'''.zh-cn=鸿雁智能墙面开关(一开) +'''HEIMAN Switch'''.zh-cn=海曼智能墙面开关(一开) +'''HEIMAN Smart Switch'''.zh-cn=海曼智能墙面开关(一开) diff --git a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy old mode 100755 new mode 100644 index ab6531e5855..e53187e617c --- a/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy +++ b/devicetypes/smartthings/zigbee-switch.src/zigbee-switch.groovy @@ -21,63 +21,83 @@ metadata { capability "Health Check" // Generic - fingerprint profileId: "C05E", deviceId: "0000", inClusters: "0006", deviceJoinName: "Generic On/Off Light", ocfDeviceType: "oic.d.light" - fingerprint profileId: "0104", deviceId: "0103", inClusters: "0006", deviceJoinName: "Generic On/Off Switch" - fingerprint profileId: "0104", deviceId: "010A", inClusters: "0006", deviceJoinName: "Generic On/Off Plug", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "C05E", deviceId: "0000", inClusters: "0006", deviceJoinName: "Light", ocfDeviceType: "oic.d.light" //Generic On/Off Light + fingerprint profileId: "0104", deviceId: "0103", inClusters: "0006", deviceJoinName: "Switch" //Generic On/Off Switch + fingerprint profileId: "0104", deviceId: "010A", inClusters: "0006", deviceJoinName: "Outlet", ocfDeviceType: "oic.d.smartplug" //Generic On/Off Plug // Centralite - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "Centralite Systems", model: "4200-C", deviceJoinName: "Centralite Smart Outlet", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "Centralite Systems", model: "4200-C", deviceJoinName: "Centralite Outlet", ocfDeviceType: "oic.d.smartplug" //Centralite Smart Outlet // eWeLink - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "eWeLink", model: "SA-003-Zigbee", deviceJoinName: "eWeLink SmartPlug (SA-003)", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "eWeLink", model: "SA-003-Zigbee", deviceJoinName: "eWeLink Outlet", ocfDeviceType: "oic.d.smartplug" //eWeLink SmartPlug (SA-003) + fingerprint profileId: "0104", inClusters: "0000,0003,0004,00005,0006", outClusters: "0000", manufacturer: "eWeLink", model: "ZB-SW01", deviceJoinName: "eWeLink Switch" + + // EZEX + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006", outClusters: "0006, 000A, 0019", model: "E220-KR1N0Z0-HA", deviceJoinName: "eZEX Switch" //EZEX Switch // GDKES - fingerprint profileId: "0104", inClusters: "0000, 0003, 0005, 0004, 0006", manufacturer: "REXENSE", model: "HY0001", deviceJoinName: "GDKES Smart Switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", manufacturer: "REXENSE", model: "RH5006", deviceJoinName: "GDKES Smart Outlet (GDKES-016)", ocfDeviceType: "oic.d.smartplug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", manufacturer: "REXENSE", model: "RH5005", deviceJoinName: "GDKES Smart Outlet (GDKES-015)", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0005, 0004, 0006", manufacturer: "REXENSE", model: "HY0001", deviceJoinName: "GDKES Switch" //GDKES Smart Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", manufacturer: "REXENSE", model: "RH5006", deviceJoinName: "GDKES Outlet", ocfDeviceType: "oic.d.smartplug" //GDKES Smart Outlet (GDKES-016) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B04", manufacturer: "REXENSE", model: "RH5005", deviceJoinName: "GDKES Outlet", ocfDeviceType: "oic.d.smartplug" //GDKES Smart Outlet (GDKES-015) + // HEIMAN + fingerprint profileId: "0104", inClusters: "0005, 0004, 0006", outClusters: "0003, 0019", manufacturer: "HEIMAN", model: "HS2SW1L-EFR-3.0", deviceJoinName: "HEIMAN Switch" //HEIMAN Smart Switch + // HONYAR - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0095", deviceJoinName: "HONYAR Smart Switch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", manufacturer: "REX", model: "HY0095", deviceJoinName: "HONYAR Switch" //HONYAR Smart Switch // IKEA - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC7C", outClusters: "0005, 0019, 0020", manufacturer:"IKEA of Sweden", model: "TRADFRI control outlet", deviceJoinName: "IKEA TRÅDFRI control outlet", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC7C", outClusters: "0005, 0019, 0020", manufacturer:"IKEA of Sweden", model: "TRADFRI control outlet", deviceJoinName: "IKEA Outlet", ocfDeviceType: "oic.d.smartplug" //IKEA TRÅDFRI control outlet // INGENIUM - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, FFFF", outClusters: "0019", manufacturer: "MEGAMAN", model: "BSZTM005", deviceJoinName: "INGENIUM ZB Mains Switching Module" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, FFFF", outClusters: "0019", manufacturer: "MEGAMAN", model: "BSZTM005", deviceJoinName: "INGENIUM Switch" //INGENIUM ZB Mains Switching Module // Innr - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "innr", model: "SP 222", deviceJoinName: "Innr Smart Plug", ocfDeviceType: "oic.d.smartplug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "innr", model: "SP 224", deviceJoinName: "Innr Smart Plug", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "innr", model: "SP 220", deviceJoinName: "Innr Outlet", ocfDeviceType: "oic.d.smartplug" //Innr Smart Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "innr", model: "SP 222", deviceJoinName: "Innr Outlet", ocfDeviceType: "oic.d.smartplug" //Innr Smart Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "innr", model: "SP 224", deviceJoinName: "Innr Outlet", ocfDeviceType: "oic.d.smartplug" //Innr Smart Plug // Lowes Iris - fingerprint profileId: "0104", inClusters: "0000, 0003, 0006, 0402, 0B05, FC01, FC02", outClusters: "0003, 0019", manufacturer: "iMagic by GreatStar", model: "1113-S", deviceJoinName: "Iris Smart Plug", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0006, 0402, 0B05, FC01, FC02", outClusters: "0003, 0019", manufacturer: "iMagic by GreatStar", model: "1113-S", deviceJoinName: "Iris Outlet", ocfDeviceType: "oic.d.smartplug" //Iris Smart Plug // Leviton - fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "000A", manufacturer: "HAI", model: "65A21-1", deviceJoinName: "Leviton Wireless Load Control Module-30amp" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL15A", deviceJoinName: "Leviton Lumina RF Plug-In Appliance Module", ocfDeviceType: "oic.d.smartplug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL15S", deviceJoinName: "Leviton Lumina RF Switch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0003, 0006, 0019, 0406", manufacturer: "Leviton", model: "ZSS-10", deviceJoinName: "Leviton Switch" //Leviton Switch + fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "000A", manufacturer: "HAI", model: "65A21-1", deviceJoinName: "Leviton Switch" //Leviton Wireless Load Control Module-30amp + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL15A", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Lumina RF Plug-In Appliance Module + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0003, 0006, 0008, 0019, 0406", manufacturer: "Leviton", model: "DL15S", deviceJoinName: "Leviton Switch" //Leviton Lumina RF Switch // Orvibo - fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "095db3379e414477ba6c2f7e0c6aa026", deviceJoinName: "Orvibo Smart Switch" - fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "fdd5fce51a164c7ab73b2f4d8d84c88e", deviceJoinName: "Orvibo Smart Outlet", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "095db3379e414477ba6c2f7e0c6aa026", deviceJoinName: "Orvibo Switch" //Orvibo Smart Switch + fingerprint profileId: "0104", inClusters: "0000, 0005, 0004, 0006", outClusters: "0000", manufacturer: "ORVIBO", model: "fdd5fce51a164c7ab73b2f4d8d84c88e", deviceJoinName: "Orvibo Outlet", ocfDeviceType: "oic.d.smartplug" //Orvibo Smart Outlet // OSRAM/SYLVANIA - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Plug 01", deviceJoinName: "OSRAM SMART+ Plug", ocfDeviceType: "oic.d.smartplug" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "PLUG", deviceJoinName: "SYLVANIA SMART+ Smart Plug", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Plug 01", deviceJoinName: "OSRAM Outlet", ocfDeviceType: "oic.d.smartplug" //OSRAM SMART+ Plug + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "PLUG", deviceJoinName: "SYLVANIA Outlet", ocfDeviceType: "oic.d.smartplug" //SYLVANIA SMART+ Smart Plug // sengled - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E1C-NB6", deviceJoinName: "Sengled Element Outlet", ocfDeviceType: "oic.d.smartplug" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E1C-NB6", deviceJoinName: "Sengled Outlet", ocfDeviceType: "oic.d.smartplug" //Sengled Element Outlet - // SONOFF - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "SONOFF", model: "BASICZBR3", deviceJoinName: "SONOFF Basic (R3 Zigbee)", ocfDeviceType: "oic.d.smartplug" + //Sinopé Technologies + fingerprint manufacturer: "Sinope Technologies", model: "SP2600ZB", deviceJoinName: "Sinope Outlet", ocfDeviceType: "oic.d.smartplug" + fingerprint manufacturer: "Sinope Technologies", model: "SP2610ZB", deviceJoinName: "Sinope Outlet", ocfDeviceType: "oic.d.smartplug" + // SONOFF + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "SONOFF", model: "BASICZBR3", deviceJoinName: "SONOFF Outlet", ocfDeviceType: "oic.d.smartplug" //SONOFF Basic (R3 Zigbee) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "0000", manufacturer: "SONOFF", model: "S31 Lite zb", deviceJoinName: "S31 Outlet", ocfDeviceType: "oic.d.smartplug" //S31 Lite zb + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006", outClusters: "1000", manufacturer: "SONOFF", model: "01MINIZB", deviceJoinName: "SONOFF 01MINIZB" //01MINIZB + // Terncy - fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0019", manufacturer: "", model: "TERNCY-LS01", deviceJoinName: "Terncy Smart Light Socket" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0006", outClusters: "0019", manufacturer: "", model: "TERNCY-LS01", deviceJoinName: "Terncy Switch" //Terncy Smart Light Socket // Third Reality - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS008Z", deviceJoinName: "RealitySwitch Plus" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS007Z", deviceJoinName: "RealitySwitch" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS008Z", deviceJoinName: "RealitySwitch Switch" //RealitySwitch Plus + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0019", manufacturer: "Third Reality, Inc", model: "3RSS007Z", deviceJoinName: "RealitySwitch Switch" //RealitySwitch + + // Dawon + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0019, 0002, 0009", manufacturer: "DAWON_DNS", model: "PM-S140-ZB", deviceJoinName: "Dawon Switch" //DAWOS DNS In-Wall Switch PM-S140-ZB + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0019, 0002, 0009", manufacturer: "DAWON_DNS", model: "PM-S140R-ZB", deviceJoinName: "Dawon Switch" //DAWOS DNS In-Wall Switch PM-S140R-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002, 0003, 0006", manufacturer: "DAWON_DNS", model: "PM-S150-ZB", deviceJoinName: "Dawon Switch" //DAWOS DNS In-Wall Switch PM-S150-ZB + fingerprint profileId: "0104", inClusters: "0000, 0002, 0003, 0006", manufacturer: "DAWON_DNS", model: "ST-S150-ZB", deviceJoinName: "Dawon Switch" //DAWOS DNS In-Wall Switch ST-S150-ZB } // simulator metadata diff --git a/devicetypes/smartthings/zigbee-thermostat.src/zigbee-thermostat.groovy b/devicetypes/smartthings/zigbee-thermostat.src/zigbee-thermostat.groovy index 2c92fa8976a..21fb393b2da 100644 --- a/devicetypes/smartthings/zigbee-thermostat.src/zigbee-thermostat.groovy +++ b/devicetypes/smartthings/zigbee-thermostat.src/zigbee-thermostat.groovy @@ -4,14 +4,12 @@ * 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 + * 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. * - * CentraLite Thermostat - * * Author: SRPOL * Date: 2018-10-15 */ @@ -36,7 +34,9 @@ metadata { capability "Refresh" capability "Sensor" - fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, 0019", manufacturer: "LUX", model: "KONOZ", deviceJoinName: "LUX KONOz Thermostat" + fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, 0019", manufacturer: "LUX", model: "KONOZ", deviceJoinName: "LUX Thermostat" //LUX KONOz Thermostat + fingerprint profileId: "0104", inClusters: "0000,0003,0020,0201,0202,0405", outClusters: "0019, 0402", manufacturer: "Umbrela", model: "Thermostat", deviceJoinName: "Umbrela Thermostat" //Umbrela UTee + fingerprint manufacturer: "Danfoss", model: "eTRV0100", deviceJoinName: "Danfoss Thermostat", vid: "SmartThings-smartthings-Danfoss_Ally_Radiator_Thermostat" //Danfoss Ally Radiator thermostat, Raw Description 01 0104 0301 01 08 0000 0001 0003 000A 0020 0201 0204 0B05 02 0000 0019 //Danfoss Thermostat } tiles { @@ -146,7 +146,7 @@ private parseAttrMessage(description) { descMap.additionalAttrs.each { attrData << [cluster: descMap.clusterInt, attribute: it.attrInt, value: it.value] } - attrData.each { + attrData.findAll( {it.value != null} ).each { def map = [:] if (it.cluster == THERMOSTAT_CLUSTER) { if (it.attribute == LOCAL_TEMPERATURE) { @@ -224,9 +224,9 @@ private parseAttrMessage(description) { * 0 – Electric / B * 1 – Gas / O */ - def cooling = intValue & 0b00000011 - def heating = (intValue & 0b00001100) >>> 2 - def heatingType = (intValue & 0b00010000) >>> 4 + def cooling = intValue & 0b00000011 + def heating = (intValue & 0b00001100) >>> 2 + def heatingType = (intValue & 0b00010000) >>> 4 def supportedModes = ["off"] if (cooling != 0x03) { @@ -262,6 +262,9 @@ private parseAttrMessage(description) { } else if (it.cluster == zigbee.POWER_CONFIGURATION_CLUSTER) { if (it.attribute == BATTERY_VOLTAGE) { map = getBatteryPercentage(Integer.parseInt(it.value, 16)) + } else if (it.attribute == BATTERY_PERCENTAGE_REMAINING) { + map.name = "battery" + map.value = Math.min(100, Integer.parseInt(it.value, 16)) } else if (it.attribute == BATTERY_ALARM_STATE) { map = getPowerSource(it.value) } @@ -278,11 +281,16 @@ private parseAttrMessage(description) { def installed() { sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) - state.supportedThermostatModes = ["off", "heat", "cool", "emergency heat"] - state.supportedFanModes = ["on", "auto"] + if (isDanfossAlly()) { + state.supportedThermostatModes = ["heat"] + } else { + state.supportedThermostatModes = ["off", "heat", "cool", "emergency heat"] + state.supportedFanModes = ["on", "auto"] + sendEvent(name: "supportedThermostatFanModes", value: JsonOutput.toJson(state.supportedFanModes), displayed: false) + sendEvent(name: "coolingSetpointRange", value: coolingSetpointRange, displayed: false) + } + sendEvent(name: "supportedThermostatModes", value: JsonOutput.toJson(state.supportedThermostatModes), displayed: false) - sendEvent(name: "supportedThermostatFanModes", value: JsonOutput.toJson(state.supportedFanModes), displayed: false) - sendEvent(name: "coolingSetpointRange", value: coolingSetpointRange, displayed: false) sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, displayed: false) } @@ -296,8 +304,16 @@ def refresh() { zigbee.readAttribute(THERMOSTAT_CLUSTER, THERMOSTAT_MODE) + zigbee.readAttribute(THERMOSTAT_CLUSTER, THERMOSTAT_RUNNING_STATE) + zigbee.readAttribute(FAN_CONTROL_CLUSTER, FAN_MODE) + - zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_VOLTAGE) + - zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_ALARM_STATE) + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_ALARM_STATE) + + getBatteryRemainingCommand() +} + +def getBatteryRemainingCommand() { + if (isDanfossAlly()) { + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_PERCENTAGE_REMAINING) + } else { + zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_VOLTAGE) + } } def ping() { @@ -306,8 +322,15 @@ def ping() { def configure() { def binding = zigbee.addBinding(THERMOSTAT_CLUSTER) + zigbee.addBinding(FAN_CONTROL_CLUSTER) - def startValues = zigbee.writeAttribute(THERMOSTAT_CLUSTER, HEATING_SETPOINT, DataType.INT16, 0x07D0) + - zigbee.writeAttribute(THERMOSTAT_CLUSTER, COOLING_SETPOINT, DataType.INT16, 0x0A28) + def startValues = zigbee.writeAttribute(THERMOSTAT_CLUSTER, HEATING_SETPOINT, DataType.INT16, 0x07D0) + + if (isDanfossAlly()) { + // setting Min/Max HeatSetPointLimits for Danfoss Ally - MinHeatSetpointLimit: 500 (0x01F4), MaxHeatSetpointLimit: 3500 (0x0DAC) + startValues += zigbee.writeAttribute(THERMOSTAT_CLUSTER, MIN_HEAT_SETPOINT_LIMIT, DataType.INT16, 0x01F4) + + zigbee.writeAttribute(THERMOSTAT_CLUSTER, MAX_HEAT_SETPOINT_LIMIT, DataType.INT16, 0x0DAC) + } else { + startValues += zigbee.writeAttribute(THERMOSTAT_CLUSTER, COOLING_SETPOINT, DataType.INT16, 0x0A28) + } return binding + startValues + zigbee.batteryConfig() + refresh() } @@ -323,20 +346,28 @@ def getBatteryPercentage(rawValue) { result.descriptionText = "${device.displayName} is powered by external source." } else { def volts = rawValue / 10 - def minVolts = 5 - def maxVolts = 6.5 + def minVolts = voltageRange.minVolts + def maxVolts = voltageRange.maxVolts def pct = (volts - minVolts) / (maxVolts - minVolts) def roundedPct = Math.round(pct * 100) if (roundedPct < 0) { roundedPct = 0 } result.value = Math.min(100, roundedPct) - result.descriptionText = "${device.displayName} battery has ${result.value}%" } return result } +def getVoltageRange() { + if (isDanfossAlly()) { + // Danfoss Ally's volage ranges: 2.4V - 0%, 3.2V - 100% (for some types of batteries it will be 3.4V - 100%) + [minVolts: 2.4, maxVolts: 3.2] + } else { + [minVolts: 5, maxVolts: 6.5] + } +} + def getTemperature(value) { if (value != null) { def celsius = Integer.parseInt(value, 16) / 100 @@ -438,33 +469,23 @@ def fanOn() { zigbee.readAttribute(FAN_CONTROL_CLUSTER, FAN_MODE) } -def setCoolingSetpoint(degrees) { - if (degrees != null) { - def celsius = (temperatureScale == "C") ? degrees : fahrenheitToCelsius(degrees) +private setSetpoint(degrees, setpointAttr, degreesMin, degreesMax) { + if (degrees != null && setpointAttr != null && degreesMin != null && degreesMax != null) { + def normalized = Math.min(degreesMax as Double, Math.max(degrees as Double, degreesMin as Double)) + def celsius = (temperatureScale == "C") ? normalized : fahrenheitToCelsius(normalized) celsius = (celsius as Double).round(2) - return zigbee.writeAttribute(THERMOSTAT_CLUSTER, COOLING_SETPOINT, DataType.INT16, hex(celsius * 100)) + - zigbee.readAttribute(THERMOSTAT_CLUSTER, COOLING_SETPOINT) + + return zigbee.writeAttribute(THERMOSTAT_CLUSTER, setpointAttr, DataType.INT16, hex(celsius * 100)) + + zigbee.readAttribute(THERMOSTAT_CLUSTER, setpointAttr) } } -def setHeatingSetpoint(degrees) { - if (degrees != null) { - def celsius = (temperatureScale == "C") ? degrees : fahrenheitToCelsius(degrees) - celsius = (celsius as Double).round(2) - - // The LUX KONOz is designed around Farenheit and doesn't show decimal temperatures. - // The lowest supported heating setpoint is 45F which is 7.22C. It displays 7C. We round - // 7.22C elsewhere to 7C. So, we want to check to make sure if the user sets 7C we send 7.22C. - // Same for the upper bounds of the heating setpoint. - if (celsius < heatingSetpointRange[0]) { - celsius = heatingSetpointRange[0] - } else if (celsius > heatingSetpointRange[1]) { - celsius = heatingSetpointRange[1] - } +def setCoolingSetpoint(degrees) { + setSetpoint(degrees, COOLING_SETPOINT, coolingSetpointRange[0], coolingSetpointRange[1]) +} - return zigbee.writeAttribute(THERMOSTAT_CLUSTER, HEATING_SETPOINT, DataType.INT16, hex(celsius * 100)) + - zigbee.readAttribute(THERMOSTAT_CLUSTER, HEATING_SETPOINT) - } +def setHeatingSetpoint(degrees) { + setSetpoint(degrees, HEATING_SETPOINT, heatingSetpointRange[0], heatingSetpointRange[1]) } private hex(value) { @@ -479,12 +500,20 @@ private boolean isLuxKONOZ() { device.getDataValue("model") == "KONOZ" } +private boolean isDanfossAlly() { + device.getDataValue("model") == "eTRV0100" +} + // TODO: Get these from the thermostat; for now they are set to match the UI metadata def getCoolingSetpointRange() { (getTemperatureScale() == "C") ? [10, 35] : [50, 95] } def getHeatingSetpointRange() { - (getTemperatureScale() == "C") ? [7.22, 32.22] : [45, 90] + if (isDanfossAlly()) { + (getTemperatureScale() == "C") ? [4, 35] : [39, 95] + } else { + (getTemperatureScale() == "C") ? [7.22, 32.22] : [45, 90] + } } private getTHERMOSTAT_CLUSTER() { 0x0201 } @@ -492,6 +521,8 @@ private getLOCAL_TEMPERATURE() { 0x0000 } private getTHERMOSTAT_SYSTEM_CONFIG() { 0x0009 } // Optional attribute private getCOOLING_SETPOINT() { 0x0011 } private getHEATING_SETPOINT() { 0x0012 } +private getMIN_HEAT_SETPOINT_LIMIT() { 0x0015 } +private getMAX_HEAT_SETPOINT_LIMIT() { 0x0016 } private getTHERMOSTAT_RUNNING_MODE() { 0x001E } private getCONTROL_SEQUENCE_OF_OPERATION() { 0x001B } // Mandatory attribute private getCONTROL_SEQUENCE_OF_OPERATION_MAP() { @@ -546,4 +577,5 @@ private getFAN_MODE_MAP() { } private getBATTERY_VOLTAGE() { 0x0020 } +private getBATTERY_PERCENTAGE_REMAINING() { 0x0021 } private getBATTERY_ALARM_STATE() { 0x003E } \ No newline at end of file diff --git a/devicetypes/smartthings/zigbee-valve.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-valve.src/i18n/messages.properties index 4b2b9611bf5..068e403b5b5 100755 --- a/devicetypes/smartthings/zigbee-valve.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-valve.src/i18n/messages.properties @@ -13,5 +13,6 @@ # under the License. # Korean (ko) # Device Preferences +'''Valve'''.ko=스마트 가스중간밸브 차단기 '''Smart Gas Valve Actuator'''.ko=스마트 가스중간밸브 차단기 #============================================================================== diff --git a/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy b/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy index a674db6bfac..a60797ac468 100644 --- a/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy +++ b/devicetypes/smartthings/zigbee-valve.src/zigbee-valve.groovy @@ -24,9 +24,9 @@ metadata { capability "Refresh" capability "Valve" - fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0006, 0020, 0B02, FC02", outClusters: "0019", manufacturer: "WAXMAN", model: "leakSMART Water Valve v2.10", deviceJoinName: "leakSMART Valve" - fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0004, 0005, 0006, 0008, 000F, 0020, 0B02", outClusters: "0003, 0019", manufacturer: "WAXMAN", model: "House Water Valve - MDL-TBD", deviceJoinName: "Waxman House Water Valve" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006, 0500", outClusters: "0019", manufacturer: "", model: "E253-KR0B0ZX-HA", deviceJoinName: "Smart Gas Valve Actuator" + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0006, 0020, 0B02, FC02", outClusters: "0019", manufacturer: "WAXMAN", model: "leakSMART Water Valve v2.10", deviceJoinName: "leakSMART Valve" //leakSMART Valve + fingerprint profileId: "0104", inClusters: "0000, 0001, 0003, 0004, 0005, 0006, 0008, 000F, 0020, 0B02", outClusters: "0003, 0019", manufacturer: "WAXMAN", model: "House Water Valve - MDL-TBD", deviceJoinName: "Waxman Valve" //Waxman House Water Valve + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0006, 0500", outClusters: "0019", manufacturer: "", model: "E253-KR0B0ZX-HA", deviceJoinName: "Valve" //Smart Gas Valve Actuator } // simulator metadata diff --git a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy index 1eec9c00b67..616a107b4d5 100644 --- a/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zigbee-white-color-temperature-bulb.src/zigbee-white-color-temperature-bulb.groovy @@ -32,69 +32,94 @@ metadata { // Generic - fingerprint profileId: "0104", deviceId: "010C", inClusters: "0006, 0008, 0300", deviceJoinName: "Generic Color Temperature Light" + fingerprint profileId: "0104", deviceId: "010C", inClusters: "0006, 0008, 0300", deviceJoinName: "Light" //Generic Color Temperature Light // ABL - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "ABL-LIGHT-Z-001", deviceJoinName: "Ultra Thin Wafer", mnmn: "Samsung Electronics", vid: "ABL-LIGHT-Z-001" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Samsung Electronics", model: "ABL-LIGHT-Z-001", deviceJoinName: "WAFER", mnmn: "Samsung Electronics", vid: "ABL-LIGHT-Z-001" //Wafer // AduroSmart - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010C", manufacturer: "AduroSmart Eria", model: "AD-ColorTemperature3001", deviceJoinName: "Eria ZigBee Color Temperature Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", deviceId: "010C", manufacturer: "AduroSmart Eria", model: "AD-ColorTemperature3001", deviceJoinName: "Eria Light" //Eria ZigBee Color Temperature Bulb // Aurora/AOne - fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300, FFFF, FFFF, 1000", outClusters: "0019", manufacturer: "Aurora", model: "TWBulb51AU", deviceJoinName: "Aurora Smart Tuneable White", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Aurora", model: "TWMPROZXBulb50AU", deviceJoinName: "Aurora MPro Smart Tuneable LED", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Aurora", model: "TWStrip50AU", deviceJoinName: "Aurora Tunable Strip Controller", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2500K-6000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "0019, 000A", manufacturer: "Aurora", model: "TWGU10Bulb50AU", deviceJoinName: "Aurora GU10 Tuneable Smart Lamp", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FFFF", outClusters: "0019", manufacturer: "Aurora", model: "TWBulb51AU", deviceJoinName: "AOne Smart Tuneable GLS Lamp", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FFFF", outClusters: "0019", manufacturer: "Aurora", model: "TWCLBulb50AU", deviceJoinName: "AOne Smart Tuneable Candle Lamp", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" + fingerprint profileId: "0104", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300, FFFF, FFFF, 1000", outClusters: "0019", manufacturer: "Aurora", model: "TWBulb51AU", deviceJoinName: "Aurora Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Aurora Smart Tuneable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Aurora", model: "TWMPROZXBulb50AU", deviceJoinName: "Aurora Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Aurora MPro Smart Tuneable LED + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Aurora", model: "TWStrip50AU", deviceJoinName: "Aurora Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2500K-6000K" //Aurora Tunable Strip Controller + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "0019, 000A", manufacturer: "Aurora", model: "TWGU10Bulb50AU", deviceJoinName: "Aurora Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Aurora GU10 Tuneable Smart Lamp + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FFFF", outClusters: "0019", manufacturer: "Aurora", model: "TWBulb51AU", deviceJoinName: "AOne Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //AOne Smart Tuneable GLS Lamp + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FFFF", outClusters: "0019", manufacturer: "Aurora", model: "TWCLBulb50AU", deviceJoinName: "AOne Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //AOne Smart Tuneable Candle Lamp + + //CWD + // raw description "01 0104 010C 01 0A 0000 0003 0004 0005 0006 0008 0300 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.A806Ecct-A001", deviceJoinName: "CWD Light" //model: "E27 Colour Tuneable", brand: "Collingwood" + // raw description "01 0104 010C 01 0A 0000 0003 0004 0005 0006 0008 0300 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.A806Bcct-A001", deviceJoinName: "CWD Light" //model: "BC Colour Tuneable", brand: "Collingwood" + // raw description "01 0104 010C 01 0A 0000 0003 0004 0005 0006 0008 0300 0B05 1000 FC82 02 000A 0019" + fingerprint manufacturer: "CWD", model: "ZB.M350cct-A001", deviceJoinName: "CWD Light" //model: "GU10 Colour Tuneable", brand: "Collingwood" // Commercial Electric - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "ETI", model: "Zigbee CCT Downlight", deviceJoinName: "Commercial Electric Can Tunable White" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "ETI", model: "Zigbee CCT Downlight", deviceJoinName: "Commercial Light", vid: "generic-color-temperature-bulb-2700K-5000K" //Commercial Electric Can Tunable White // Ecosmart - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "The Home Depot", model: "Ecosmart-ZBT-BR30-CCT-Bulb", deviceJoinName: "Ecosmart Bulb" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "The Home Depot", model: "Ecosmart-ZBT-A19-CCT-Bulb", deviceJoinName: "Ecosmart Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "The Home Depot", model: "Ecosmart-ZBT-BR30-CCT-Bulb", deviceJoinName: "Ecosmart Light" //Ecosmart Bulb + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "The Home Depot", model: "Ecosmart-ZBT-A19-CCT-Bulb", deviceJoinName: "Ecosmart Light" //Ecosmart Bulb + + // Ikea + fingerprint manufacturer: "IKEA of Sweden", model: "GUNNARP panel round", deviceJoinName: "IKEA Light" , mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //01 0104 010C 01 08 0000 0003 0004 0005 0006 0008 0300 1000 04 0005 0019 0020 1000 //IKEA GUNNARP Lamp + fingerprint manufacturer: "IKEA of Sweden", model: "LEPTITER Recessed spot light", deviceJoinName: "IKEA Light" , mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //01 0104 010C 01 08 0000 0003 0004 0005 0006 0008 0300 1000 04 0005 0019 0020 1000 //IKEA LEPTITER Spotlight + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E12 WS opal 600lm", deviceJoinName: "IKEA Light" , mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //01 0104 010C 01 09 0000 0003 0004 0005 0006 0008 0300 1000 FC7C 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E14 WS 470lm", deviceJoinName: "IKEA Light" , mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //01 0104 010C 01 08 0000 0003 0004 0005 0006 0008 0300 1000 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E14 WS opal 600lm", deviceJoinName: "IKEA Light" , mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //01 0104 010C 01 09 0000 0003 0004 0005 0006 0008 0300 1000 FC7C 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 WS clear 806lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" // raw desc: 01 0104 010C 01 08 0000 0003 0004 0005 0006 0008 0300 1000 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WS clear 806lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" // raw desc: 01 0104 010C 01 08 0000 0003 0004 0005 0006 0008 0300 1000 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 WS opal 1000lm", deviceJoinName: "IKEA Light" , mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //01 0104 010C 01 09 0000 0003 0004 0005 0006 0008 0300 1000 FC7C 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb + fingerprint manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WS opal 1000lm", deviceJoinName: "IKEA Light" , mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //01 0104 010C 01 09 0000 0003 0004 0005 0006 0008 0300 1000 FC7C 04 0005 0019 0020 1000 //IKEA TRÅDFRI LED Bulb // INGENIUM - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Megaman", model: "Z3-ColorTemperature", deviceJoinName: "INGENIUM ZB Color Temperature Light" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Megaman", model: "Z3-ColorTemperature", deviceJoinName: "INGENIUM Light" //INGENIUM ZB Color Temperature Light // Innr - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 248 T", deviceJoinName: "Innr Smart Candle Comfort", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 278 T", deviceJoinName: "Innr Smart Bulb Comfort", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RS 228 T", deviceJoinName: "Innr Smart Spot Comfort", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 248 T", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Innr Smart Candle Comfort + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 278 T", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Innr Smart Bulb Comfort + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "innr", model: "RS 228 T", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Innr Smart Spot Comfort // OSRAM/SYLVANIA (LEDVANCE) - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "SYLVANIA Smart BR30 Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "SYLVANIA Smart RT5/6 Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM SMART+ LED Classic A60 Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "SYLVANIA Smart A19 Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic B40 TW - LIGHTIFY", deviceJoinName: "OSRAM SMART+ Classic B40 Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "A19 TW 10 year", deviceJoinName: "SYLVANIA Smart 10Y A19 TW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Conv Under Cabinet TW", deviceJoinName: "SYLVANIA Smart Convertible Under Cabinet" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "ColorstripRGBW", deviceJoinName: "SYLVANIA Smart Convertible Under Cabinet" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Edge-lit Flushmount TW", deviceJoinName: "SYLVANIA Smart Edge-lit Flushmount TW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "MR16 TW", deviceJoinName: "SYLVANIA Smart MR16 Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Surface TW", deviceJoinName: "SYLVANIA Smart Surface Tunable White" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Under Cabinet TW", deviceJoinName: "SYLVANIA Smart Under Cabinet TW" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "BR30 TW", deviceJoinName: "SYLVANIA Smart+ Adustable White BR30" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "RT TW", deviceJoinName: "SYLVANIA Smart+ Adustable White RT5/6" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Edge-lit flushmount", deviceJoinName: "SYLVANIA SMART+ Flush Mount" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY BR Tunable White", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart BR30 Tunable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY RT Tunable White", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart RT5/6 Tunable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 TW", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Classic A60 Tunable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 Tunable White", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart A19 Tunable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic B40 TW - LIGHTIFY", deviceJoinName: "OSRAM Light" //OSRAM SMART+ Classic B40 Tunable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, 0B05, FC01, FC08", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "A19 TW 10 year", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart 10Y A19 TW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Conv Under Cabinet TW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Convertible Under Cabinet + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "ColorstripRGBW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Convertible Under Cabinet + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Edge-lit Flushmount TW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Edge-lit Flushmount TW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0003, 0019", manufacturer: "LEDVANCE", model: "MR16 TW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart MR16 Tunable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Surface TW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Surface Tunable White + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Under Cabinet TW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart Under Cabinet TW + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "BR30 TW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart+ Adustable White BR30 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, FC01", outClusters: "0019", manufacturer: "LEDVANCE", model: "RT TW", deviceJoinName: "SYLVANIA Light" //SYLVANIA Smart+ Adustable White RT5/6 + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Edge-lit flushmount", deviceJoinName: "SYLVANIA Light", mnmn: "SmartThings", vid: "generic-color-temperature-ceiling-light-2700K-6500K" //SYLVANIA SMART+ Flush Mount // Leedarson - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Smarthome", model: "S111-202A", deviceJoinName: "Leedarson Tunable White Bulb A19" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Smarthome", model: "S111-202A", deviceJoinName: "Leedarson Light" //Leedarson Tunable White Bulb A19 + + // LINKIND + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000, FC82", outClusters: "000A, 0019", manufacturer: "lk", model: "ZBT-CCTLight-GLS0108", deviceJoinName: "Linkind Light" //Linkid Tunable A19 Bulb // Muller Licht Tint - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "MLI", model: "ZBT-ColorTemperature", deviceJoinName: "Müller Licht Tint White Bulb" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "MLI", model: "ZBT-ColorTemperature", deviceJoinName: "Tint Light" //Müller Licht Tint White Bulb // Sengled - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A19NAE26", deviceJoinName: "Sengled Element Plus" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A191AE26W", deviceJoinName: "Sengled Element Plus" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A60EAB22", deviceJoinName: "Sengled Element Plus" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A60EAE27", deviceJoinName: "Sengled Element Plus" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A19NAE26", deviceJoinName: "Sengled Light" //Sengled Element Plus + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A191AE26W", deviceJoinName: "Sengled Light" //Sengled Element Plus + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A60EAB22", deviceJoinName: "Sengled Light" //Sengled Element Plus + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "Z01-A60EAE27", deviceJoinName: "Sengled Light" //Sengled Element Plus // Third Reality - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RSL011Z", deviceJoinName: "RealityLight" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RSL012Z", deviceJoinName: "RealityLight" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RSL011Z", deviceJoinName: "RealityLight Light" //RealityLight + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "Third Reality, Inc", model: "3RSL012Z", deviceJoinName: "RealityLight Light" //RealityLight + + // Ajax Online + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Ajax Online", model: "CCT", deviceJoinName: "Ajax Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-6500K" // Ajax Online Filament Bulb } // UI tile definitions diff --git a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy index 965c3cee01b..797ddd4f432 100644 --- a/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy +++ b/devicetypes/smartthings/zigbee-window-shade-battery.src/zigbee-window-shade-battery.groovy @@ -15,19 +15,24 @@ import groovy.json.JsonOutput import physicalgraph.zigbee.zcl.DataType metadata { - definition(name: "ZigBee Window Shade Battery", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-shade-2") { + definition(name: "ZigBee Window Shade Battery", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-shade-3") { capability "Actuator" capability "Battery" capability "Configuration" capability "Refresh" capability "Window Shade" + capability "Window Shade Preset" capability "Health Check" capability "Switch Level" command "pause" - fingerprint manufacturer: "IKEA of Sweden", model: "KADRILJ roller blind", deviceJoinName: "IKEA KADRILJ Blinds" // raw description 01 0104 0202 00 09 0000 0001 0003 0004 0005 0020 0102 1000 FC7C 02 0019 1000 - fingerprint manufacturer: "IKEA of Sweden", model: "FYRTUR block-out roller blind", deviceJoinName: "IKEA FYRTUR Blinds" // raw description 01 0104 0202 01 09 0000 0001 0003 0004 0005 0020 0102 1000 FC7C 02 0019 1000 + fingerprint manufacturer: "IKEA of Sweden", model: "KADRILJ roller blind", deviceJoinName: "IKEA Window Treatment" // raw description 01 0104 0202 00 09 0000 0001 0003 0004 0005 0020 0102 1000 FC7C 02 0019 1000 //IKEA KADRILJ Blinds + fingerprint manufacturer: "IKEA of Sweden", model: "FYRTUR block-out roller blind", deviceJoinName: "IKEA Window Treatment" // raw description 01 0104 0202 01 09 0000 0001 0003 0004 0005 0020 0102 1000 FC7C 02 0019 1000 //IKEA FYRTUR Blinds + } + + preferences { + input "preset", "number", title: "Preset position", description: "Set the window shade preset position", defaultValue: 50, range: "1..100", required: false, displayDuringSetup: false } tiles(scale: 2) { @@ -43,6 +48,9 @@ metadata { standardTile("contPause", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "pause", label:"", icon:'st.sonos.pause-btn', action:'pause', backgroundColor:"#cccccc" } + standardTile("presetPosition", "device.presetPosition", width: 2, height: 2, decoration: "flat") { + state "default", label: "Preset", action:"presetPosition", icon:"st.Home.home2" + } standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" } @@ -57,7 +65,7 @@ metadata { } main "windowShade" - details(["windowShade", "contPause", "shadeLevel", "levelSliderControl", "refresh", "batteryLevel"]) + details(["windowShade", "contPause", "presetPosition", "shadeLevel", "levelSliderControl", "refresh", "batteryLevel"]) } } @@ -155,12 +163,12 @@ def batteryPercentageEventHandler(batteryLevel) { def close() { log.info "close()" - zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_CLOSE) + setLevel(0) } def open() { log.info "open()" - zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_OPEN) + setLevel(100) } def setLevel(data, rate = null) { @@ -176,14 +184,22 @@ def setLevel(data, rate = null) { } else { cmd = zigbee.command(zigbee.LEVEL_CONTROL_CLUSTER, COMMAND_MOVE_LEVEL_ONOFF, zigbee.convertToHexString(Math.round(data * 255 / 100), 2)) } - return cmd + cmd } def pause() { log.info "pause()" + // If the window shade isn't moving when we receive a pause() command then just echo back the current state for the mobile client. + if (device.currentValue("windowShade") != "opening" && device.currentValue("windowShade") != "closing") { + sendEvent(name: "windowShade", value: device.currentValue("windowShade"), isStateChange: true, displayed: false) + } zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) } +def presetPosition() { + setLevel(preset ?: 50) +} + /** * PING is used by Device-Watch in attempt to reach the Device * */ @@ -210,7 +226,7 @@ def configure() { def cmds if (supportsLiftPercentage()) { - cmds = zigbee.configureReporting(CLUSTER_WINDOW_COVERING, ATTRIBUTE_POSITION_LIFT, DataType.UINT8, 0, 600, null) + cmds = zigbee.configureReporting(CLUSTER_WINDOW_COVERING, ATTRIBUTE_POSITION_LIFT, DataType.UINT8, 2, 600, null) } else { cmds = zigbee.levelConfig() } @@ -272,4 +288,4 @@ def isIkeaKadrilj() { def isIkeaFyrtur() { device.getDataValue("model") == "FYRTUR block-out roller blind" -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/zigbee-window-shade.src/i18n/messages.properties b/devicetypes/smartthings/zigbee-window-shade.src/i18n/messages.properties index 514a57bff50..0a1a5605dfb 100755 --- a/devicetypes/smartthings/zigbee-window-shade.src/i18n/messages.properties +++ b/devicetypes/smartthings/zigbee-window-shade.src/i18n/messages.properties @@ -13,6 +13,9 @@ # under the License. # Chinese +'''Wistar Window Treatment'''.zh-cn=威仕达开合帘电机(CMJ) '''Wistar Curtain Motor(CMJ)'''.zh-cn=威仕达开合帘电机(CMJ) +'''Window Treatment'''.zh-cn=智能窗帘电机(DT82TV) '''Smart Curtain Motor(DT82TV)'''.zh-cn=智能窗帘电机(DT82TV) +'''Window Treatment'''.zh-cn=智能窗帘电机(BCM300D) '''Smart Curtain Motor(BCM300D)'''.zh-cn=智能窗帘电机(BCM300D) diff --git a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy index 1aa28f9d0c6..705c2520288 100755 --- a/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy +++ b/devicetypes/smartthings/zigbee-window-shade.src/zigbee-window-shade.groovy @@ -18,20 +18,26 @@ import physicalgraph.zigbee.zcl.DataType metadata { definition(name: "ZigBee Window Shade", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-shade") { capability "Actuator" - capability "Battery" capability "Configuration" capability "Refresh" capability "Window Shade" + capability "Window Shade Preset" capability "Health Check" capability "Switch Level" command "pause" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0102", outClusters: "0019", model: "E2B0-KR000Z0-HA", deviceJoinName: "SOMFY Blind Controller/eZEX" // SY-IoT201-BD - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.6", deviceJoinName: "Wistar Curtain Motor(CMJ)" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.8", deviceJoinName: "Wistar Curtain Motor(CMJ)" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0102", outClusters: "0003", manufacturer: "REXENSE", model: "KG0001", deviceJoinName: "Smart Curtain Motor(BCM300D)" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0102", outClusters: "0003", manufacturer: "REXENSE", model: "DY0010", deviceJoinName: "Smart Curtain Motor(DT82TV)" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0102", outClusters: "0019", model: "E2B0-KR000Z0-HA", deviceJoinName: "eZEX Window Treatment" // SY-IoT201-BD //SOMFY Blind Controller/eZEX + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.6", deviceJoinName: "Wistar Window Treatment" //Wistar Curtain Motor(CMJ) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0102", outClusters: "000A", manufacturer: "Feibit Co.Ltd", model: "FTB56-ZT218AK1.8", deviceJoinName: "Wistar Window Treatment" //Wistar Curtain Motor(CMJ) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0102", outClusters: "0003", manufacturer: "REXENSE", model: "KG0001", deviceJoinName: "Window Treatment" //Smart Curtain Motor(BCM300D) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0102", outClusters: "0003", manufacturer: "REXENSE", model: "DY0010", deviceJoinName: "Window Treatment" //Smart Curtain Motor(DT82TV) + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0102", outClusters: "0003", manufacturer: "SOMFY", model: "Curtain", deviceJoinName: "Somfy Window Treatment" //Somfy Glydea Ultra + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0020, 0102", outClusters: "0003", manufacturer: "SOMFY", model: "Roller", deviceJoinName: "Somfy Window Treatment" // Somfy Sonesse 30 Zigbee LI-ION Pack + } + + preferences { + input "preset", "number", title: "Preset position", description: "Set the window shade preset position", defaultValue: 50, range: "1..100", required: false, displayDuringSetup: false } tiles(scale: 2) { @@ -47,6 +53,9 @@ metadata { standardTile("contPause", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "pause", label:"", icon:'st.sonos.pause-btn', action:'pause', backgroundColor:"#cccccc" } + standardTile("presetPosition", "device.presetPosition", width: 2, height: 2, decoration: "flat") { + state "default", label: "Preset", action:"presetPosition", icon:"st.Home.home2" + } standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" } @@ -58,7 +67,7 @@ metadata { } main "windowShade" - details(["windowShade", "contPause", "shadeLevel", "levelSliderControl", "refresh"]) + details(["windowShade", "contPause", "presetPosition", "shadeLevel", "levelSliderControl", "refresh"]) } } @@ -70,7 +79,6 @@ private getCOMMAND_GOTO_LIFT_PERCENTAGE() { 0x05 } private getATTRIBUTE_POSITION_LIFT() { 0x0008 } private getATTRIBUTE_CURRENT_LEVEL() { 0x0000 } private getCOMMAND_MOVE_LEVEL_ONOFF() { 0x04 } -private getBATTERY_PERCENTAGE_REMAINING() { 0x0021 } private List collectAttributes(Map descMap) { List descMaps = new ArrayList() @@ -107,9 +115,6 @@ def parse(String description) { def valueInt = Math.round((zigbee.convertHexToInt(descMap.value)) / 255 * 100) levelEventHandler(valueInt) - } else if (reportsBatteryPercentage() && descMap?.clusterInt == zigbee.POWER_CONFIGURATION_CLUSTER && zigbee.convertHexToInt(descMap?.attrId) == BATTERY_PERCENTAGE_REMAINING && descMap.value) { - def batteryLevel = zigbee.convertHexToInt(descMap.value) - batteryPercentageEventHandler(batteryLevel) } } } @@ -142,13 +147,6 @@ def updateFinalState() { } } -def batteryPercentageEventHandler(batteryLevel) { - if (batteryLevel != null) { - batteryLevel = Math.min(100, Math.max(0, batteryLevel)) - sendEvent([name: "battery", value: batteryLevel, unit: "%", descriptionText: "{{ device.displayName }} battery was {{ value }}%"]) - } -} - def supportsLiftPercentage() { device.getDataValue("manufacturer") != "Feibit Co.Ltd" } @@ -181,7 +179,17 @@ def setLevel(data, rate = null) { def pause() { log.info "pause()" - zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) + def currentShadeStatus = device.currentValue("windowShade") + + if (currentShadeStatus == "open" || currentShadeStatus == "closed") { + sendEvent(name: "windowShade", value: currentShadeStatus) + } else { + zigbee.command(CLUSTER_WINDOW_COVERING, COMMAND_PAUSE) + } +} + +def presetPosition() { + setLevel(preset ?: 50) } /** @@ -223,17 +231,9 @@ def configure() { cmds += readDeviceBindingTable() } - if (reportsBatteryPercentage()) { - cmds += zigbee.configureReporting(zigbee.POWER_CONFIGURATION_CLUSTER, BATTERY_PERCENTAGE_REMAINING, DataType.UINT8, 30, 21600, 0x01) - } - return refresh() + cmds } -def usesLocalGroupBinding() { - isIkeaKadrilj() || isIkeaFyrtur() -} - private def parseBindingTableMessage(description) { Integer groupAddr = getGroupAddrFromBindingTable(description) if (groupAddr) { @@ -259,17 +259,9 @@ private List readDeviceBindingTable() { } def shouldInvertLiftPercentage() { - return isIkeaKadrilj() || isIkeaFyrtur() + return isSomfy() } -def reportsBatteryPercentage() { - return isIkeaKadrilj() || isIkeaFyrtur() -} - -def isIkeaKadrilj() { - device.getDataValue("model") == "KADRILJ roller blind" -} - -def isIkeaFyrtur() { - device.getDataValue("model") == "FYRTUR block-out roller blind" -} +def isSomfy() { + device.getDataValue("manufacturer") == "SOMFY" +} \ No newline at end of file diff --git a/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy b/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy index 1b903686e07..9a62821d25a 100644 --- a/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy +++ b/devicetypes/smartthings/zll-dimmer-bulb.src/zll-dimmer-bulb.groovy @@ -23,48 +23,49 @@ metadata { capability "Health Check" // Generic - fingerprint profileId: "C05E", deviceId: "0100", inClusters: "0006, 0008", deviceJoinName: "Generic Dimmable Light" + fingerprint profileId: "C05E", deviceId: "0100", inClusters: "0006, 0008", deviceJoinName: "Light" //Generic Dimmable Light // AduroSmart - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF, 0019", outClusters: "0019", deviceId: "0100", manufacturer: "AduroSmart Eria", model: "ZLL-DimmableLight", deviceJoinName: "Eria ZLL Dimmable Bulb" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF, 0019", outClusters: "0019", deviceId: "0100", manufacturer: "AduroSmart Eria", model: "ZLL-DimmableLight", deviceJoinName: "Eria Light" //Eria ZLL Dimmable Bulb // IKEA - fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 opal 1000lm", deviceJoinName: "IKEA TRÅDFRI LED Bulb" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E12 W op/ch 400lm", deviceJoinName: "IKEA TRÅDFRI LED Bulb" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E17 W op/ch 400lm", deviceJoinName: "IKEA TRÅDFRI LED Bulb" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb GU10 W 400lm", deviceJoinName: "IKEA TRÅDFRI LED Bulb" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 W opal 1000lm", deviceJoinName: "IKEA TRÅDFRI LED Bulb" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E14 W op/ch 400lm", deviceJoinName: "IKEA TRÅDFRI LED Bulb" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI transformer 10W", deviceJoinName: "IKEA TRÅDFRI Driver for wireless control 10W" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI Driver 10W", deviceJoinName: "IKEA TRÅDFRI Driver for wireless control 10W" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI transformer 30W", deviceJoinName: "IKEA TRÅDFRI Driver for wireless control 30W" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI Driver 30W", deviceJoinName: "IKEA TRÅDFRI Driver for wireless control 30W" + fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 opal 1000lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E12 W op/ch 400lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E17 W op/ch 400lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb GU10 W 400lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 W opal 1000lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 W opal 1000lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E14 W op/ch 400lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI transformer 10W", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI Driver for wireless control 10W + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI Driver 10W", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI Driver for wireless control 10W + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI transformer 30W", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI Driver for wireless control 30W + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI Driver 30W", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI Driver for wireless control 30W // INGENIUM - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF", outClusters: "0019",manufacturer: "Megaman", model: "ZLL-DimmableLight", deviceJoinName: "INGENIUM ZB Dimmable Light" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF", outClusters: "0019",manufacturer: "MEGAMAN", model: "BSZTM002", deviceJoinName: "INGENIUM ZB Dimmable A60 Bulb" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF", outClusters: "0019",manufacturer: "MEGAMAN", model: "BSZTM003", deviceJoinName: "INGENIUM ZB Dimming Module" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF", outClusters: "0019",manufacturer: "Megaman", model: "ZLL-DimmableLight", deviceJoinName: "INGENIUM Light" //INGENIUM ZB Dimmable Light + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF", outClusters: "0019",manufacturer: "MEGAMAN", model: "BSZTM002", deviceJoinName: "INGENIUM Light" //INGENIUM ZB Dimmable A60 Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FFFF", outClusters: "0019",manufacturer: "MEGAMAN", model: "BSZTM003", deviceJoinName: "INGENIUM Light" //INGENIUM ZB Dimming Module // Innr - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RS 125", deviceJoinName: "Innr Smart Spot White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RB 165", deviceJoinName: "Innr Smart Bulb White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RB 175 W", deviceJoinName: "Innr Smart Bulb Warm Dimming" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RB 145", deviceJoinName: "Innr Smart Candle White" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RS 125", deviceJoinName: "Innr Light" //Innr Smart Spot White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RB 165", deviceJoinName: "Innr Light" //Innr Smart Bulb White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RB 175 W", deviceJoinName: "Innr Light" //Innr Smart Bulb Warm Dimming + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "innr", model: "RB 145", deviceJoinName: "Innr Light" //Innr Smart Candle White // OSRAM - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 W clear", deviceJoinName: "OSRAM SMART+ LED Smart Connected Light" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 W clear - LIGHTIFY", deviceJoinName: "OSRAM SMART+ LED Smart Connected Light" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "CLA60 OFD OSRAM", deviceJoinName: "OSRAM SMART+ LED Classic A60 Dimming" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 W clear", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Smart Connected Light + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic A60 W clear - LIGHTIFY", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Smart Connected Light + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "CLA60 OFD OSRAM", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Classic A60 Dimming // Philips Hue - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB004", deviceJoinName: "Philips Hue White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB006", deviceJoinName: "Philips Hue White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB007", deviceJoinName: "Philips Hue White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB010", deviceJoinName: "Philips Hue White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB014", deviceJoinName: "Philips Hue White" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB004", deviceJoinName: "Philips Light" //Philips Hue White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB006", deviceJoinName: "Philips Light" //Philips Hue White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB007", deviceJoinName: "Philips Light" //Philips Hue White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB010", deviceJoinName: "Philips Light" //Philips Hue White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "Philips", model: "LWB014", deviceJoinName: "Philips Light" //Philips Hue White // Sengled - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E14-U43", deviceJoinName: "Sengled E14-U43" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E14-U43", deviceJoinName: "Sengled Light" //Sengled E14-U43 } // simulator metadata @@ -167,4 +168,4 @@ def configure() { def updated() { log.debug "updated()" configureHealthCheck() -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/zll-rgb-bulb.src/zll-rgb-bulb.groovy b/devicetypes/smartthings/zll-rgb-bulb.src/zll-rgb-bulb.groovy index 8a07fd6de98..04a9522c91d 100644 --- a/devicetypes/smartthings/zll-rgb-bulb.src/zll-rgb-bulb.groovy +++ b/devicetypes/smartthings/zll-rgb-bulb.src/zll-rgb-bulb.groovy @@ -26,11 +26,11 @@ metadata { capability "Health Check" // Generic - fingerprint profileId: "C05E", deviceId: "0200", inClusters: "0006, 0008, 0300", deviceJoinName: "Generic RGB Light" + fingerprint profileId: "C05E", deviceId: "0200", inClusters: "0006, 0008, 0300", deviceJoinName: "Light" //Generic RGB Light // IKEA - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 CWS opal 600lm", deviceJoinName: "IKEA TRÅDFRI bulb E27 CWS opal 600lm" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 CWS opal 600lm", deviceJoinName: "IKEA TRÅDFRI bulb E26 CWS opal 600lm" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 CWS opal 600lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI bulb E27 CWS opal 600lm + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 CWS opal 600lm", deviceJoinName: "IKEA Light" //IKEA TRÅDFRI bulb E26 CWS opal 600lm } // UI tile definitions diff --git a/devicetypes/smartthings/zll-rgbw-bulb.src/zll-rgbw-bulb.groovy b/devicetypes/smartthings/zll-rgbw-bulb.src/zll-rgbw-bulb.groovy index ba762254ea4..e3cb42aa128 100644 --- a/devicetypes/smartthings/zll-rgbw-bulb.src/zll-rgbw-bulb.groovy +++ b/devicetypes/smartthings/zll-rgbw-bulb.src/zll-rgbw-bulb.groovy @@ -30,43 +30,49 @@ metadata { attribute "colorName", "string" // Generic - fingerprint profileId: "C05E", deviceId: "0210", inClusters: "0006, 0008, 0300", deviceJoinName: "Generic RGBW Light" + fingerprint profileId: "C05E", deviceId: "0210", inClusters: "0006, 0008, 0300", deviceJoinName: "Light" //Generic RGBW Light // AduroSmart - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FFFF, 0019", outClusters: "0019", deviceId: "0210", manufacturer: "AduroSmart Eria", model: "ZLL-ExtendedColor", deviceJoinName: "Eria ZLL RGBW Bulb" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FFFF, 0019", outClusters: "0019", deviceId: "0210", manufacturer: "AduroSmart Eria", model: "ZLL-ExtendedColor", deviceJoinName: "Eria Light" //Eria ZLL RGBW Bulb + + // GLEDOPTO + fingerprint manufacturer: "GLEDOPTO", model: "GL-C-008", deviceJoinName: "Gledopto Switch", ocfDeviceType: "oic.d.switch" // raw description 0B C05E 0210 02 07 0000 0003 0004 0005 0006 0008 0300 00 //Gledopto RGB+CCT LED Controller // INGENIUM - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FFFF", outClusters: "0019", manufacturer: "Megaman", model: "ZLL-ExtendedColor", deviceJoinName: "INGENIUM ZB RGBW Light" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FFFF", outClusters: "0019", manufacturer: "Megaman", model: "ZLL-ExtendedColor", deviceJoinName: "INGENIUM Light" //INGENIUM ZB RGBW Light // Innr - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RB 185 C", deviceJoinName: "Innr Smart Bulb Color" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "FL 130 C", deviceJoinName: "Innr Flex Light Color" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RB 185 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" //Innr Smart Bulb Color + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "FL 130 C", deviceJoinName: "Innr Light" //Innr Flex Light Color + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "OFL 120 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Outdoor Flex Light Colour 2m + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "OFL 140 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Outdoor Flex Light Colour 4m + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "OSL 130 C", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-1800K-6500K" //Innr Smart Outdoor Spot Light Colour OSL 130 C // OSRAM - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", "manufacturer":"OSRAM", "model":"Classic A60 RGBW", deviceJoinName: "OSRAM SMART+ LED Classic A60 RGBW" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "PAR 16 50 RGBW - LIGHTIFY", deviceJoinName: "OSRAM SMART+ RGBW PAR 16 50" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "CLA60 RGBW OSRAM", deviceJoinName: "OSRAM SMART+ LED Classic A60 RGBW" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Flex RGBW", deviceJoinName: "OSRAM SMART+ Flex RGBW" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenpole RGBW-Lightify", deviceJoinName: "OSRAM SMART+ Gardenpole RGBW" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Outdoor Flex RGBW", deviceJoinName: "OSRAM SMART+ Outdoor Flex RGBW" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Indoor Flex RGBW", deviceJoinName: "OSRAM SMART+ Indoor Flex RGBW", mnmn:"SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", "manufacturer":"OSRAM", "model":"Classic A60 RGBW", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Classic A60 RGBW + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "PAR 16 50 RGBW - LIGHTIFY", deviceJoinName: "OSRAM Light" //OSRAM SMART+ RGBW PAR 16 50 + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "CLA60 RGBW OSRAM", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Classic A60 RGBW + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Flex RGBW", deviceJoinName: "OSRAM Light" //OSRAM SMART+ Flex RGBW + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Gardenpole RGBW-Lightify", deviceJoinName: "OSRAM Light" //OSRAM SMART+ Gardenpole RGBW + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Outdoor Flex RGBW", deviceJoinName: "OSRAM Light" //OSRAM SMART+ Outdoor Flex RGBW + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000,FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY Indoor Flex RGBW", deviceJoinName: "OSRAM Light", mnmn: "SmartThings", vid: "generic-rgbw-color-bulb-2000K-6500K" //OSRAM SMART+ Indoor Flex RGBW // Philips Hue - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT001", deviceJoinName: "Philips Hue A19" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT002", deviceJoinName: "Philips Hue BR30" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT003", deviceJoinName: "Philips Hue GU10" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT007", deviceJoinName: "Philips Hue A19" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT010", deviceJoinName: "Philips Hue A19" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT011", deviceJoinName: "Philips Hue BR30" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT012", deviceJoinName: "Philips Hue Candle" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT014", deviceJoinName: "Philips Hue A19" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT015", deviceJoinName: "Philips Hue A19" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT016", deviceJoinName: "Philips Hue A19" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LST001", deviceJoinName: "Philips Hue Lightstrip" - fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LST002", deviceJoinName: "Philips Hue Lightstrip" + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT001", deviceJoinName: "Philips Light" //Philips Hue A19 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT002", deviceJoinName: "Philips Light" //Philips Hue BR30 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT003", deviceJoinName: "Philips Light" //Philips Hue GU10 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT007", deviceJoinName: "Philips Light" //Philips Hue A19 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT010", deviceJoinName: "Philips Light" //Philips Hue A19 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT011", deviceJoinName: "Philips Light" //Philips Hue BR30 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT012", deviceJoinName: "Philips Light" //Philips Hue Candle + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT014", deviceJoinName: "Philips Light" //Philips Hue A19 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT015", deviceJoinName: "Philips Light" //Philips Hue A19 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LCT016", deviceJoinName: "Philips Light" //Philips Hue A19 + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LST001", deviceJoinName: "Philips Light" //Philips Hue Lightstrip + fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,0300,1000", outClusters: "0019", manufacturer: "Philips", model: "LST002", deviceJoinName: "Philips Light" //Philips Hue Lightstrip //XLSmart - fingerprint profileId: "C05E", manufacturer: "GLEDOPTO", model: "GL-B-001Z", deviceJoinName: "XLSmart E14 RGBW Light Bulb" + fingerprint profileId: "C05E", manufacturer: "GLEDOPTO", model: "GL-B-001Z", deviceJoinName: "XLSmart Light" //XLSmart E14 RGBW Light Bulb } // UI tile definitions @@ -208,6 +214,10 @@ def updated() { def installed() { sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) configureHealthCheck() + + if (isInnr185C()) { + sendHubCommand(zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND, getScaledHue(0), getScaledSaturation(0), "0000")) + } } def setColorTemperature(value) { @@ -269,4 +279,8 @@ def setSaturation(value) { //payload-> sat value, transition time zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) -} \ No newline at end of file +} + +private boolean isInnr185C() { + device.getDataValue("model") == "RB 185 C" +} diff --git a/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy b/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy index fee44ddb53f..df05829bd7c 100644 --- a/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy +++ b/devicetypes/smartthings/zll-white-color-temperature-bulb-5000k.src/zll-white-color-temperature-bulb-5000k.groovy @@ -27,21 +27,21 @@ metadata { attribute "colorName", "string" // Eaton - fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "Eaton", model: "Halo_RL5601", deviceJoinName: "Halo RL56" + fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "Eaton", model: "Halo_RL5601", deviceJoinName: "Halo Light" //Halo RL56 // Ikea - fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 WS clear 950lm", deviceJoinName: "IKEA TRÅDFRI White Spectrum LED Bulb", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb GU10 WS 400lm", deviceJoinName: "IKEA TRÅDFRI White Spectrum LED Bulb", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E12 WS opal 400lm", deviceJoinName: "IKEA TRÅDFRI White Spectrum LED Bulb", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 WS opal 980lm", deviceJoinName: "IKEA TRÅDFRI White Spectrum LED Bulb", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WS clear 950lm", deviceJoinName: "IKEA TRÅDFRI White Spectrum LED Bulb", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E14 WS opal 400lm", deviceJoinName: "IKEA TRÅDFRI White Spectrum LED Bulb", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WS opal 980lm", deviceJoinName: "IKEA TRÅDFRI White Spectrum LED Bulb", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" + fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 WS clear 950lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA TRÅDFRI White Spectrum LED Bulb + fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb GU10 WS 400lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA TRÅDFRI White Spectrum LED Bulb + fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E12 WS opal 400lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA TRÅDFRI White Spectrum LED Bulb + fingerprint inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E26 WS opal 980lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA TRÅDFRI White Spectrum LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WS clear 950lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA TRÅDFRI White Spectrum LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E14 WS opal 400lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA TRÅDFRI White Spectrum LED Bulb + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "TRADFRI bulb E27 WS opal 980lm", deviceJoinName: "IKEA Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA TRÅDFRI White Spectrum LED Bulb // Innr - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RS 128 T", deviceJoinName: "Innr Smart Spot Tunable White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RB 178 T", deviceJoinName: "Innr Smart Bulb Tunable White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RB 148 T", deviceJoinName: "Innr Smart Bulb Tunable White" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RS 128 T", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Innr Smart Spot Tunable White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RB 178 T", deviceJoinName: "Innr Light" //Innr Smart Bulb Tunable White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300", outClusters: "0019", manufacturer: "innr", model: "RB 148 T", deviceJoinName: "Innr Light", mnmn: "SmartThings", vid: "generic-color-temperature-bulb-2200K-5000K" //Innr Smart Bulb Tunable White } // UI tile definitions diff --git a/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy b/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy index ae75d7bc828..f42b8f2c5d8 100644 --- a/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/zll-white-color-temperature-bulb.src/zll-white-color-temperature-bulb.groovy @@ -27,35 +27,37 @@ metadata { attribute "colorName", "string" // Generic - fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0006, 0008, 0300", deviceJoinName: "Generic Color Temperature Light" + fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0006, 0008, 0300", deviceJoinName: "Light" //Generic Color Temperature Light // AduraSmart - fingerprint profileId: "C05E", deviceId: "0220", manufacturer: "AduroSmart Eria", model: "ZLL-ColorTemperature", deviceJoinName: "Eria Color temperature light" - fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FFFF, 0019", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "ZLL-ColorTemperature", deviceJoinName: "Eria ZLL Color Temperature Bulb", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-6500K" + fingerprint profileId: "C05E", deviceId: "0220", manufacturer: "AduroSmart Eria", model: "ZLL-ColorTemperature", deviceJoinName: "Eria Light" //Eria Color temperature light + fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, FFFF, 0019", outClusters: "0019", manufacturer: "AduroSmart Eria", model: "ZLL-ColorTemperature", deviceJoinName: "Eria Light", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-6500K" //Eria ZLL Color Temperature Bulb // IKEA - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "FLOALT panel WS 30x30", deviceJoinName: "IKEA FLOALT Panel", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "SURTE door WS 38x64", deviceJoinName: "IKEA SURTE Panel", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "JORMLIEN door WS 40x80", deviceJoinName: "IKEA JORMLIEN Panel", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "FLOALT panel WS 30x30", deviceJoinName: "IKEA Light", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA FLOALT Panel + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "FLOALT panel WS 30x90", deviceJoinName: "IKEA Light", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA FLOALT Panel + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "FLOALT panel WS 60x60", deviceJoinName: "IKEA Light", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA FLOALT Panel + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "SURTE door WS 38x64", deviceJoinName: "IKEA Light", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA SURTE Panel + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 0B05, 1000", outClusters: "0005, 0019, 0020, 1000", manufacturer: "IKEA of Sweden", model: "JORMLIEN door WS 40x80", deviceJoinName: "IKEA Light", mnmn:"SmartThings", vid: "generic-color-temperature-bulb-2200K-4000K" //IKEA JORMLIEN Panel // OSRAM - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, 0B04, FC0F", outClusters: "0019", "manufacturer": "OSRAM", "model": "Classic A60 TW", deviceJoinName: "OSRAM SMART+ LED Classic A60 Tunable White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", "manufacturer": "OSRAM", "model": "PAR16 50 TW", deviceJoinName: "OSRAM SMART+ LED PAR16 50 Tunable White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic B40 TW - LIGHTIFY", deviceJoinName: "OSRAM SMART+ Classic B40 Tunable White" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "CLA60 TW OSRAM", deviceJoinName: "OSRAM SMART+ LED Classic A60 Tunable White" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, 0B04, FC0F", outClusters: "0019", "manufacturer": "OSRAM", "model": "Classic A60 TW", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Classic A60 Tunable White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", "manufacturer": "OSRAM", "model": "PAR16 50 TW", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED PAR16 50 Tunable White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "Classic B40 TW - LIGHTIFY", deviceJoinName: "OSRAM Light" //OSRAM SMART+ Classic B40 Tunable White + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "CLA60 TW OSRAM", deviceJoinName: "OSRAM Light" //OSRAM SMART+ LED Classic A60 Tunable White // Philips Hue - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW001", deviceJoinName: "Philips Hue White Ambiance A19" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW004", deviceJoinName: "Philips Hue White Ambiance A19" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW010", deviceJoinName: "Philips Hue White Ambiance A19" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW011", deviceJoinName: "Philips Hue White Ambiance BR30" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW012", deviceJoinName: "Philips Hue White Ambiance Candle" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW013", deviceJoinName: "Philips Hue White Ambiance Spot" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW014", deviceJoinName: "Philips Hue White Ambiance Spot" - fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW015", deviceJoinName: "Philips Hue White Ambiance A19" + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW001", deviceJoinName: "Philips Light" //Philips Hue White Ambiance A19 + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW004", deviceJoinName: "Philips Light" //Philips Hue White Ambiance A19 + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW010", deviceJoinName: "Philips Light" //Philips Hue White Ambiance A19 + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW011", deviceJoinName: "Philips Light" //Philips Hue White Ambiance BR30 + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW012", deviceJoinName: "Philips Light" //Philips Hue White Ambiance Candle + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW013", deviceJoinName: "Philips Light" //Philips Hue White Ambiance Spot + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW014", deviceJoinName: "Philips Light" //Philips Hue White Ambiance Spot + fingerprint profileId: "C05E", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0300, 1000", outClusters: "0019", manufacturer: "Philips", model: "LTW015", deviceJoinName: "Philips Light" //Philips Hue White Ambiance A19 // XLSmart - fingerprint profileId: "C05E", manufacturer: "Ubec", model: "BBB65L-HY", deviceJoinName: "XLSmart E27 Light Bulb" + fingerprint profileId: "C05E", manufacturer: "Ubec", model: "BBB65L-HY", deviceJoinName: "XLSmart Light" //XLSmart E27 Light Bulb } // UI tile definitions diff --git a/devicetypes/smartthings/zooz-4-in-1-sensor.src/zooz-4-in-1-sensor.groovy b/devicetypes/smartthings/zooz-4-in-1-sensor.src/zooz-4-in-1-sensor.groovy index 301b09d3636..9e79a63a7b0 100644 --- a/devicetypes/smartthings/zooz-4-in-1-sensor.src/zooz-4-in-1-sensor.groovy +++ b/devicetypes/smartthings/zooz-4-in-1-sensor.src/zooz-4-in-1-sensor.groovy @@ -23,7 +23,9 @@ metadata { capability "Health Check" capability "Tamper Alert" - fingerprint mfr: "027A", prod: "2021", model: "2101", deviceJoinName: "Zooz 4-in-1 sensor" + fingerprint mfr: "027A", prod: "2021", model: "2101", deviceJoinName: "Zooz Multipurpose Sensor" // Zooz 4-in-1 sensor + fingerprint mfr: "0109", prod: "2021", model: "2101", deviceJoinName: "Vision Multipurpose Sensor" // ZP3111US 4-in-1 Motion + fingerprint mfr: "0060", prod: "0001", model: "0004", deviceJoinName: "Everspring Motion Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-Everspring_Multisensor" // Everspring Immune Pet PIR Sensor SP815 } tiles(scale: 2) { @@ -62,8 +64,36 @@ metadata { main(["motion", "temperature", "humidity", "illuminance"]) details(["motion", "temperature", "humidity", "illuminance", "battery", "tamper"]) } + + preferences { + section { + input( + title: "Settings Available For Everspring SP815 only", + description: "To apply updated device settings to the device press the learn key on the device three times or check the device manual.", + type: "paragraph", + element: "paragraph" + ) + input( + title: "Temperature and Humidity Auto Report (Everspring SP815 only):", + description: "This setting allows to adjusts report time (in seconds) of temperature and humidity report.", + name: "temperatureAndHumidityReport", + type: "number", + range: "600..1440", + defaultValue: 600 + ) + input( + title: "Re-trigger Interval Setting (Everspring SP815 only):", + description: "The setting adjusts the sleep period (in seconds) after the detector has been triggered. No response will be made during this interval if a movement is presented. Longer re-trigger interval will result in longer battery life.", + name: "retriggerIntervalSettings", + type: "number", + range: "10..3600", + defaultValue: 180 + ) + } + } } + def initialize() { sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) clearTamper() @@ -75,6 +105,7 @@ def installed() { def updated() { initialize() + getConfigurationCommands() } def parse(String description) { @@ -94,6 +125,12 @@ def parse(String description) { def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { def results = [] results += createEvent(descriptionText: "$device.displayName woke up", isStateChange: false) + + log.debug "isConfigured: $state.configured" + if (isEverspringSP815() && !state.configured) { + results += lateConfigure() + } + results += response([ secure(zwave.batteryV1.batteryGet()), "delay 2000", @@ -181,6 +218,7 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm } else { result = createEvent(descriptionText: cmd.toString(), isStateChange: false) } + return result } @@ -193,12 +231,21 @@ def ping() { } def configure() { + if (isEverspringSP815()) { + state.configured = false + state.intervalConfigured = false + state.temperatureConfigured = false + } def request = [] request << zwave.batteryV1.batteryGet() request << zwave.notificationV3.notificationGet(notificationType: 0x07, event: 0x08) //motion request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature - request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) //humidity + if (isEverspringSP815()) { + request += getConfigurationCommands() + } else { + request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance + } secureSequence(request) + ["delay 20000", zwave.wakeUpV2.wakeUpNoMoreInformation().format()] } @@ -235,3 +282,70 @@ private secure(physicalgraph.zwave.Command cmd) { private secureSequence(commands, delay = 200) { delayBetween(commands.collect{ secure(it) }, delay) } + +def getConfigurationCommands() { + log.debug "getConfigurationCommands" + def result = [] + + if (isEverspringSP815()) { + Integer temperatureAndHumidityReport = (settings.temperatureAndHumidityReport as Integer) ?: everspringDefaults[1] + Integer retriggerIntervalSettings = (settings.retriggerIntervalSettings as Integer) ?: everspringDefaults[2] + + if (!state.temperatureAndHumidityReport) { + state.temperatureAndHumidityReport = getEverspringDefaults[1] + } + if (!state.retriggerIntervalSettings) { + state.retriggerIntervalSettings = getEverspringDefaults[2] + } + + if (!state.configured || (temperatureAndHumidityReport != state.temperatureAndHumidityReport || retriggerIntervalSettings != state.retriggerIntervalSettings)) { + state.configured = false // this flag needs to be set to false when settings are changed (and the device was initially configured before) + + if (!state.temperatureConfigured || temperatureAndHumidityReport != state.temperatureAndHumidityReport) { + state.temperatureConfigured = false + result << zwave.configurationV2.configurationSet(parameterNumber: 1, size: 2, scaledConfigurationValue: temperatureAndHumidityReport) + result << zwave.configurationV2.configurationGet(parameterNumber: 1) + } + if (!state.intervalConfigured || retriggerIntervalSettings != state.retriggerIntervalSettings) { + state.intervalConfigured = false + result << zwave.configurationV2.configurationSet(parameterNumber: 2, size: 2, scaledConfigurationValue: retriggerIntervalSettings) + result << zwave.configurationV2.configurationGet(parameterNumber: 2) + } + } + } + + return result +} + +def getEverspringDefaults() { + [1: 600, + 2: 180] +} + +def lateConfigure() { + log.debug "lateConfigure" + sendHubCommand(getConfigurationCommands(), 200) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + if (isEverspringSP815()) { + if (cmd.parameterNumber == 1) { + state.temperatureAndHumidityReport = scaledConfigurationValue + state.temperatureConfigured = true + } else if (cmd.parameterNumber == 2) { + state.retriggerIntervalSettings = scaledConfigurationValue + state.intervalConfigured = true + } + + if (state.intervalConfigured && state.temperatureConfigured) { + state.configured = true + } + log.debug "Everspring Configuration Report: ${cmd}" + } + + return [:] +} + +private isEverspringSP815() { + zwaveInfo?.mfr?.equals("0060") && zwaveInfo?.model?.equals("0004") +} diff --git a/devicetypes/smartthings/zooz-multisiren.src/zooz-multisiren.groovy b/devicetypes/smartthings/zooz-multisiren.src/zooz-multisiren.groovy index e172e4921b5..7a4765a99d0 100644 --- a/devicetypes/smartthings/zooz-multisiren.src/zooz-multisiren.groovy +++ b/devicetypes/smartthings/zooz-multisiren.src/zooz-multisiren.groovy @@ -29,8 +29,8 @@ metadata { capability "Refresh" capability "Configuration" - fingerprint mfr: "027A", prod: "000C", model: "0003", deviceJoinName: "Zooz S2 Multisiren ZSE19" - fingerprint mfr: "0060", prod: "000C", model: "0003", deviceJoinName: "Everspring Indoor Voice Siren" + fingerprint mfr: "027A", prod: "000C", model: "0003", deviceJoinName: "Zooz Siren" //Zooz S2 Multisiren ZSE19 + fingerprint mfr: "0060", prod: "000C", model: "0003", deviceJoinName: "Everspring Siren" //Everspring Indoor Voice Siren } diff --git a/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy b/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy index c424edc93af..b757d703424 100644 --- a/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy +++ b/devicetypes/smartthings/zooz-power-strip.src/zooz-power-strip.groovy @@ -20,14 +20,14 @@ * */ metadata { - definition (name: "Zooz Power Strip", namespace: "smartthings", author: "SmartThings") { + definition (name: "Zooz Power Strip", namespace: "smartthings", author: "SmartThings", mcdSync: true) { capability "Switch" capability "Refresh" capability "Actuator" capability "Sensor" capability "Configuration" - fingerprint manufacturer: "015D", prod: "0651", model: "F51C", deviceJoinName: "Zooz ZEN 20 Power Strip" + fingerprint manufacturer: "015D", prod: "0651", model: "F51C", deviceJoinName: "Zooz Outlet" //Zooz ZEN 20 Power Strip } tiles { @@ -92,6 +92,14 @@ def parse(String description) { } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) if (encapsulatedCommand) { zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) diff --git a/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy b/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy index 4b0969abdfb..4a858dfb065 100644 --- a/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy +++ b/devicetypes/smartthings/zwave-basic-heat-alarm.src/zwave-basic-heat-alarm.groovy @@ -19,7 +19,7 @@ metadata { capability "Health Check" //zw:S type:0701 mfr:026F prod:0001 model:0002 ver:1.07 zwv:4.24 lib:03 cc:5E,86,72,5A,73,80,71,85,59,84 role:06 ff:8C01 ui:8C01 - fingerprint mfr: "026F ", prod: "0001", model: "0002", deviceJoinName: "FireAngel Thermistek Alarm" + fingerprint mfr: "026F ", prod: "0001", model: "0002", deviceJoinName: "FireAngel Smoke Detector" //FireAngel Thermistek Alarm } simulator { @@ -158,7 +158,7 @@ def createHeatEvents(name) { } private command(physicalgraph.zwave.Command cmd) { - if (zwaveInfo?.zw?.endsWith("s")) { + if (zwaveInfo?.zw?.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() diff --git a/devicetypes/smartthings/zwave-basic-smoke-alarm.src/zwave-basic-smoke-alarm.groovy b/devicetypes/smartthings/zwave-basic-smoke-alarm.src/zwave-basic-smoke-alarm.groovy index 93a5772acf4..d6e4ff5a592 100644 --- a/devicetypes/smartthings/zwave-basic-smoke-alarm.src/zwave-basic-smoke-alarm.groovy +++ b/devicetypes/smartthings/zwave-basic-smoke-alarm.src/zwave-basic-smoke-alarm.groovy @@ -18,12 +18,13 @@ metadata { capability "Battery" capability "Health Check" - fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86" - fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector" + fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86", deviceJoinName: "Smoke Detector" + fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector" //First Alert Smoke Detector //zw:S type:0701 mfr:026F prod:0001 model:0001 ver:1.07 zwv:4.24 lib:03 cc:5E,86,72,5A,73,80,71,85,59,84 role:06 ff:8C01 ui:8C01 - fingerprint mfr: "026F ", prod: "0001", model: "0001", deviceJoinName: "FireAngel Thermoptek Smoke Alarm" - fingerprint mfr: "013C", prod: "0002", model: "001E", deviceJoinName: "Philio Smoke Alarm PSG01" - fingerprint mfr: "0154", prod: "0004", model: "0010", deviceJoinName: "POPP 10Year Smoke Sensor" + fingerprint mfr: "026F ", prod: "0001", model: "0001", deviceJoinName: "FireAngel Smoke Detector" //FireAngel Thermoptek Smoke Alarm + fingerprint mfr: "013C", prod: "0002", model: "001E", deviceJoinName: "Philio Smoke Detector" //Philio Smoke Alarm PSG01 + fingerprint mfr: "0154", prod: "0004", model: "0010", deviceJoinName: "POPP Smoke Detector" //POPP 10Year Smoke Sensor + fingerprint mfr: "0154", prod: "0100", model: "0201", deviceJoinName: "POPP Smoke Detector" //POPP Smoke Detector with Siren } simulator { @@ -190,13 +191,16 @@ def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd, def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd, results) { results << createEvent(descriptionText: "$device.displayName woke up", isStateChange: false) if (!state.lastbatt || (now() - state.lastbatt) >= 56*60*60*1000) { - results << response([ + results << response(delayBetween([ + zwave.notificationV3.notificationGet(notificationType: 0x01).format(), zwave.batteryV1.batteryGet().format(), - "delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format() - ]) + ], 2000)) } else { - results << response(zwave.wakeUpV1.wakeUpNoMoreInformation()) + results << response(delayBetween([ + zwave.notificationV3.notificationGet(notificationType: 0x01).format(), + zwave.wakeUpV1.wakeUpNoMoreInformation().format() + ], 2000)) } } @@ -232,7 +236,7 @@ def zwaveEvent(physicalgraph.zwave.Command cmd, results) { } private command(physicalgraph.zwave.Command cmd) { - if (zwaveInfo?.zw?.endsWith("s")) { + if (zwaveInfo?.zw?.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() @@ -248,5 +252,6 @@ def initialPoll() { // check initial battery and smoke sensor state request << zwave.batteryV1.batteryGet() request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_SMOKE) + if (zwaveInfo.mfr != "0138") request << zwave.wakeUpV1.wakeUpIntervalSet(seconds: 4*60*60, nodeid: zwaveHubNodeId) commands(request, 500) + ["delay 6000", command(zwave.wakeUpV1.wakeUpNoMoreInformation())] } diff --git a/devicetypes/smartthings/zwave-basic-window-shade.src/zwave-basic-window-shade.groovy b/devicetypes/smartthings/zwave-basic-window-shade.src/zwave-basic-window-shade.groovy new file mode 100644 index 00000000000..7276b9a52f8 --- /dev/null +++ b/devicetypes/smartthings/zwave-basic-window-shade.src/zwave-basic-window-shade.groovy @@ -0,0 +1,195 @@ +/** + * Copyright 2019 SRPOL + * + * 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. + * + */ + +import groovy.json.JsonOutput + +metadata { + definition (name: "Z-Wave Basic Window Shade", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.blind", mnmn: "SmartThings", vid: "generic-stateless-curtain") { + capability "Stateless Curtain Power Button" + capability "Configuration" + capability "Actuator" + capability "Health Check" + + command "open" + command "close" + command "pause" + + fingerprint mfr:"0086", prod:"0003", model:"008D", deviceJoinName: "Aeotec Window Treatment" //Aeotec Nano Shutter + fingerprint mfr:"0086", prod:"0103", model:"008D", deviceJoinName: "Aeotec Window Treatment" //Aeotec Nano Shutter + fingerprint mfr:"0371", prod:"0003", model:"008D", deviceJoinName: "Aeotec Window Treatment" //Aeotec Nano Shutter + fingerprint mfr:"0371", prod:"0103", model:"008D", deviceJoinName: "Aeotec Window Treatment" //Aeotec Nano Shutter + } + + tiles(scale: 2) { + standardTile("open", "device.open", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'Open', action:"open" + } + standardTile("close", "device.close", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'Close', action:"close" + } + standardTile("pause", "device.pause", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label:'Pause', action:"pause" + } + + details(["open","close","pause"]) + } + + preferences { + section { + input(title: "Aeotec Nano Shutter settings", + description: "In case wiring is wrong, this setting can be changed to fix setup without any manual maintenance.", + displayDuringSetup: false, + type: "paragraph", + element: "paragraph") + + input("reverseDirection", "bool", + title: "Reverse working direction", + defaultValue: false, + displayDuringSetup: false + ) + + //This setting for calibrationTime is specific to Aeotec Nano Shutter and operates under def updated() - Line 159 + input("calibrationTime", "number", + title: "Open/Close timing", + description: "Set the motor's open/close time", + defaultValue: false, + displayDuringSetup: false, + range: "5..255", + default: 10 + ) + } + } +} + +def parse(String description) { + log.debug "parse() - description: $description" + def result = [] + if (description.startsWith("Err")) { + result = createEvent(descriptionText:description, isStateChange:true) + } else { + def cmd = zwave.parse(description) + if (cmd) { + result += zwaveEvent(cmd) + } + } + log.debug "Parse returned: ${result}" + result +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + log.debug "Security Message Encap ${cmd}" + def encapsulatedCommand = cmd.encapsulatedCommand() + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + if (!state.ignoreResponse) + state.shadeState = (cmd.value == closeValue ? "closing" : "opening") + + state.ignoreResponse = false + [:] +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.warn "Unhandled ${cmd}" + createEvent(descriptionText: "An event came in") +} + +def setButton(button) { + log.debug "button: $button" + switch(button) { + case "open": + case "statelessCurtainPowerButton_open_button": + open() + break + case "close": + case "statelessCurtainPowerButton_close_button": + close() + break + default: + pause() + break + } +} + +def open() { + state.shadeState = "opening" + secure(zwave.basicV1.basicSet(value: openValue)) +} + +def close() { + state.shadeState = "closing" + secure(zwave.basicV1.basicSet(value: closeValue)) +} + +def pause() { + def value = state.shadeState == "opening" ? closeValue : openValue + def result = state.shadeState != "paused" ? secure(zwave.switchBinaryV1.switchBinarySet(switchValue: value)) : [] + state.ignoreResponse = true + state.shadeState = "paused" + result +} + +def ping() { + secure(zwave.switchMultilevelV3.switchMultilevelGet()) +} + +def installed() { + log.debug "Installed ${device.displayName}" + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + sendEvent(name: "availableCurtainPowerButtons", value: JsonOutput.toJson(["open", "close", "pause"]), displayed: false) + state.shadeState = "paused" + state.reverseDirection = reverseDirection ? reverseDirection : false +} + +def updated() { + sendHubCommand(pause()) + state.reverseDirection = reverseDirection ? reverseDirection : false + + if (calibrationTime >= 5 && calibrationTime <= 255) { + response([ + secure(zwave.configurationV1.configurationSet(parameterNumber: 35, size: 1, scaledConfigurationValue: calibrationTime)), + ]) + } + +} + +def configure() { + log.debug "Configure..." + response([ + secure(zwave.configurationV1.configurationSet(parameterNumber: 80, size: 1, scaledConfigurationValue: 1)), + secure(zwave.configurationV1.configurationSet(parameterNumber: 85, size: 1, scaledConfigurationValue: 1)) + ]) +} + +private secure(cmd) { + if(zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } +} + +private getOpenValue() { + !state.reverseDirection ? 0x00 : 0xFF +} + +private getCloseValue() { + !state.reverseDirection ? 0xFF : 0x00 +} diff --git a/devicetypes/smartthings/zwave-battery-thermostat.src/zwave-battery-thermostat.groovy b/devicetypes/smartthings/zwave-battery-thermostat.src/zwave-battery-thermostat.groovy index cf55caaa33e..b800ff6684b 100644 --- a/devicetypes/smartthings/zwave-battery-thermostat.src/zwave-battery-thermostat.groovy +++ b/devicetypes/smartthings/zwave-battery-thermostat.src/zwave-battery-thermostat.groovy @@ -12,7 +12,9 @@ * */ metadata { - definition (name: "Z-Wave Battery Thermostat", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.thermostat", genericHandler: "Z-Wave") { + definition (name: "Z-Wave Battery Thermostat", namespace: "smartthings", author: "SmartThings", + ocfDeviceType: "oic.d.thermostat", genericHandler: "Z-Wave", runLocally: true, + executeCommandsLocally: false, minHubCoreVersion: '000.033.0001') { capability "Actuator" capability "Temperature Measurement" capability "Thermostat Heating Setpoint" @@ -20,12 +22,13 @@ metadata { capability "Thermostat Operating State" capability "Thermostat Mode" capability "Thermostat Fan Mode" + capability "Relative Humidity Measurement" capability "Configuration" capability "Refresh" capability "Sensor" capability "Health Check" capability "Battery" - + attribute "thermostatFanState", "string" command "switchMode" @@ -35,9 +38,10 @@ metadata { command "lowerCoolSetpoint" command "raiseCoolSetpoint" - fingerprint inClusters: "0x43,0x40,0x44,0x31,0x80" - fingerprint mfr: "014F", prod: "5442", model: "5431", deviceJoinName: "Linear Z-Wave Thermostat" - fingerprint mfr: "014F", prod: "5442", model: "5436", deviceJoinName: "GoControl Z-Wave Thermostat" + fingerprint inClusters: "0x43,0x40,0x44,0x31,0x80", deviceJoinName: "Thermostat" + fingerprint mfr: "014F", prod: "5442", model: "5431", deviceJoinName: "Linear Thermostat" //Linear Z-Wave Thermostat + fingerprint mfr: "014F", prod: "5442", model: "5436", deviceJoinName: "GoControl Thermostat" //GoControl Z-Wave Thermostat + fingerprint mfr: "0039", prod: "0011", model: "0008", deviceJoinName: "Honeywell Thermostat" //Honeywell T6 Pro Z-Wave Thermostat } tiles { @@ -114,9 +118,9 @@ metadata { def installed() { // Configure device - def cmds = [new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format())] + def cmds = [zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId])] sendHubCommand(cmds) - runIn(3, "initialize", [overwrite: true]) // Allow configure command to be sent and acknowledged before proceeding + runIn(3, "initialize", [overwrite: true, forceForLocallyExecuting: true]) // Allow configure command to be sent and acknowledged before proceeding } def updated() { @@ -127,11 +131,14 @@ def initialize() { // Device-Watch simply pings if no device events received for 24hrs sendEvent(name: "checkInterval", value: 60 * 60 * 24, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) unschedule() + sendHubCommand([ + zwave.thermostatModeV2.thermostatModeSupportedGet(), + zwave.thermostatFanModeV3.thermostatFanModeSupportedGet() + ]) pollDevice() } def configure() { - def cmds = [] /* Configuration of reporting values. Bitmask based on: 1 TEMPERATURE (CC_SENSOR_MULTILEVEL) @@ -149,7 +156,7 @@ def configure() { 16384 MECH STATUS 32768 SCP STATUS */ - cmds << zwave.configurationV1.configurationSet(parameterNumber: 23, size: 2, scaledConfigurationValue: 8319).format() + response(zwave.configurationV1.configurationSet(parameterNumber: 23, size: 2, scaledConfigurationValue: 8319)) } def parse(String description) @@ -179,11 +186,9 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpo switch (cmd.setpointType) { case 1: sendEvent(name: "heatingSetpoint", value: setpoint, unit: unit, displayed: false) - updateThermostatSetpoint("heatingSetpoint", setpoint) break; case 2: sendEvent(name: "coolingSetpoint", value: setpoint, unit: unit, displayed: false) - updateThermostatSetpoint("coolingSetpoint", setpoint) break; default: log.debug "unknown setpointType $cmd.setpointType" @@ -203,7 +208,6 @@ def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv3.SensorMultilevelR map.value = getTempInLocalScale(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C") map.unit = getTemperatureScale() map.name = "temperature" - updateThermostatSetpoint(null, null) } else if (cmd.sensorType == 5) { map.value = cmd.scaledSensorValue map.unit = "%" @@ -238,7 +242,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev1.Thermosta break } // Makes sure we have the correct thermostat mode - sendHubCommand(new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())) + sendHubCommand(zwave.thermostatModeV2.thermostatModeGet()) createEvent(map) } @@ -259,7 +263,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatfanstatev1.ThermostatFanSt } def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) { - def map = [name: "thermostatMode", data:[supportedThermostatModes: state.supportedModes]] + def map = [name: "thermostatMode"] switch (cmd.mode) { case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_OFF: map.value = "off" @@ -277,12 +281,11 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeRepor map.value = "auto" break } - updateThermostatSetpoint(null, null) createEvent(map) } def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) { - def map = [name: "thermostatFanMode", data:[supportedThermostatFanModes: state.supportedFanModes]] + def map = [name: "thermostatFanMode"] switch (cmd.fanMode) { case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW: map.value = "auto" @@ -348,21 +351,20 @@ def refresh() { if (!state.refreshTriggeredAt || (2 * 60 * 1000 < (timeNow - state.refreshTriggeredAt))) { state.refreshTriggeredAt = timeNow // use runIn with overwrite to prevent multiple DTH instances run before state.refreshTriggeredAt has been saved - runIn(2, "pollDevice", [overwrite: true]) + runIn(2, "pollDevice", [overwrite: true, forceForLocallyExecuting: true]) } } def pollDevice() { def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSupportedGet().format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format()) - cmds << new physicalgraph.device.HubAction(zwave.sensorMultilevelV2.sensorMultilevelGet().format()) // current temperature - cmds << new physicalgraph.device.HubAction(zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()) - cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format()) - cmds << new physicalgraph.device.HubAction(zwave.batteryV1.batteryGet().format()) + cmds << zwave.thermostatModeV2.thermostatModeGet() + cmds << zwave.thermostatFanModeV3.thermostatFanModeGet() + cmds << zwave.sensorMultilevelV2.sensorMultilevelGet(sensorType: 1) // current temperature + cmds << zwave.sensorMultilevelV2.sensorMultilevelGet(sensorType: 5) // current relative humidity + cmds << zwave.thermostatOperatingStateV1.thermostatOperatingStateGet() + cmds << zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1) + cmds << zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2) + cmds << zwave.batteryV1.batteryGet() sendHubCommand(cmds, 1200) } @@ -404,11 +406,11 @@ def alterSetpoint(raise, setpoint) { unit: getTemperatureScale(), eventType: "ENTITY_UPDATE", displayed: false) } if (data.targetHeatingSetpoint && data.targetCoolingSetpoint) { - runIn(5, "updateHeatingSetpoint", [data: data, overwrite: true]) + runIn(5, "updateHeatingSetpoint", [data: data, overwrite: true, forceForLocallyExecuting: true]) } else if (setpoint == "heatingSetpoint" && data.targetHeatingSetpoint) { - runIn(5, "updateHeatingSetpoint", [data: data, overwrite: true]) + runIn(5, "updateHeatingSetpoint", [data: data, overwrite: true, forceForLocallyExecuting: true]) } else if (setpoint == "coolingSetpoint" && data.targetCoolingSetpoint) { - runIn(5, "updateCoolingSetpoint", [data: data, overwrite: true]) + runIn(5, "updateCoolingSetpoint", [data: data, overwrite: true, forceForLocallyExecuting: true]) } } @@ -421,7 +423,7 @@ def updateCoolingSetpoint(data) { } def enforceSetpointLimits(setpoint, data) { - def locationScale = getTemperatureScale() + def locationScale = getTemperatureScale() def minSetpoint = (setpoint == "heatingSetpoint") ? getTempInDeviceScale(40, "F") : getTempInDeviceScale(50, "F") def maxSetpoint = (setpoint == "heatingSetpoint") ? getTempInDeviceScale(90, "F") : getTempInDeviceScale(99, "F") def deadband = (state.scale == 1) ? 3 : 2 // 3°F, 2°C @@ -436,7 +438,7 @@ def enforceSetpointLimits(setpoint, data) { } // Enforce 3 degrees F deadband between setpoints if (setpoint == "heatingSetpoint") { - heatingSetpoint = targetValue + heatingSetpoint = targetValue coolingSetpoint = (heatingSetpoint + deadband > getTempInDeviceScale(data.coolingSetpoint, locationScale)) ? heatingSetpoint + deadband : null } if (setpoint == "coolingSetpoint") { @@ -449,14 +451,14 @@ def enforceSetpointLimits(setpoint, data) { def setHeatingSetpoint(degrees) { if (degrees) { state.heatingSetpoint = degrees.toDouble() - runIn(2, "updateSetpoints", [overwrite: true]) + runIn(2, "updateSetpoints", [overwrite: true, forceForLocallyExecuting: true]) } } def setCoolingSetpoint(degrees) { if (degrees) { state.coolingSetpoint = degrees.toDouble() - runIn(2, "updateSetpoints", [overwrite: true]) + runIn(2, "updateSetpoints", [overwrite: true, forceForLocallyExecuting: true]) } } @@ -496,33 +498,13 @@ def updateSetpoints(data) { sendHubCommand(cmds, 1000) } -// thermostatSetpoint is not displayed by any tile as it can't be predictable calculated due to -// the device's quirkiness but it is defined by the capability so it must be set, set it to the most likely value -def updateThermostatSetpoint(setpoint, value) { - def scale = getTemperatureScale() - def heatingSetpoint = (setpoint == "heatingSetpoint") ? value : getTempInLocalScale("heatingSetpoint") - def coolingSetpoint = (setpoint == "coolingSetpoint") ? value : getTempInLocalScale("coolingSetpoint") - def mode = device.currentValue("thermostatMode") - def thermostatSetpoint = heatingSetpoint // corresponds to (mode == "heat" || mode == "emergency heat") - if (mode == "cool") { - thermostatSetpoint = coolingSetpoint - } else if (mode == "auto" || mode == "off") { - // Set thermostatSetpoint to the setpoint closest to the current temperature - def currentTemperature = getTempInLocalScale("temperature") - if (currentTemperature > (heatingSetpoint + coolingSetpoint)/2) { - thermostatSetpoint = coolingSetpoint - } - } - sendEvent(name: "thermostatSetpoint", value: thermostatSetpoint, unit: getTemperatureScale()) -} - /** * PING is used by Device-Watch in attempt to reach the Device * */ def ping() { log.debug "ping() called" // Just get Operating State there's no need to flood more commands - sendHubCommand(new physicalgraph.device.HubAction(zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format())) + sendHubCommand(zwave.thermostatOperatingStateV1.thermostatOperatingStateGet()) } def switchMode() { @@ -532,7 +514,7 @@ def switchMode() { if (supportedModes && supportedModes.size() && supportedModes[0].size() > 1) { def next = { supportedModes[supportedModes.indexOf(it) + 1] ?: supportedModes[0] } def nextMode = next(currentMode) - runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true, forceForLocallyExecuting: true]) } else { log.warn "supportedModes not defined" getSupportedModes() @@ -544,7 +526,7 @@ def switchToMode(nextMode) { // Old version of supportedModes was as string, make sure it gets updated if (supportedModes && supportedModes.size() && supportedModes[0].size() > 1) { if (supportedModes.contains(nextMode)) { - runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true, forceForLocallyExecuting: true]) } else { log.debug("ThermostatMode $nextMode is not supported by ${device.displayName}") } @@ -556,7 +538,7 @@ def switchToMode(nextMode) { def getSupportedModes() { def cmds = [] - cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSupportedGet().format()) + cmds << zwave.thermostatModeV2.thermostatModeSupportedGet() sendHubCommand(cmds) } @@ -567,7 +549,7 @@ def switchFanMode() { if (supportedFanModes && supportedFanModes.size() && supportedFanModes[0].size() > 1) { def next = { supportedFanModes[supportedFanModes.indexOf(it) + 1] ?: supportedFanModes[0] } def nextMode = next(currentMode) - runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true, forceForLocallyExecuting: true]) } else { log.warn "supportedFanModes not defined" getSupportedFanModes() @@ -579,7 +561,7 @@ def switchToFanMode(nextMode) { // Old version of supportedFanModes was as string, make sure it gets updated if (supportedFanModes && supportedFanModes.size() && supportedFanModes[0].size() > 1) { if (supportedFanModes.contains(nextMode)) { - runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true]) + runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true, forceForLocallyExecuting: true]) } else { log.debug("FanMode $nextMode is not supported by ${device.displayName}") } @@ -590,7 +572,7 @@ def switchToFanMode(nextMode) { } def getSupportedFanModes() { - def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())] + def cmds = [zwave.thermostatFanModeV3.thermostatFanModeSupportedGet()] sendHubCommand(cmds) } @@ -607,8 +589,8 @@ def setThermostatMode(String value) { } def setGetThermostatMode(data) { - def cmds = [new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format()), - new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())] + def cmds = [zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]), + zwave.thermostatModeV2.thermostatModeGet()] sendHubCommand(cmds) } @@ -623,8 +605,8 @@ def setThermostatFanMode(String value) { } def setGetThermostatFanMode(data) { - def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format()), - new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())] + def cmds = [zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]), + zwave.thermostatFanModeV3.thermostatFanModeGet()] sendHubCommand(cmds) } diff --git a/devicetypes/smartthings/zwave-button.src/zwave-button.groovy b/devicetypes/smartthings/zwave-button.src/zwave-button.groovy index ef8b31f94a1..c564d8b7e54 100644 --- a/devicetypes/smartthings/zwave-button.src/zwave-button.groovy +++ b/devicetypes/smartthings/zwave-button.src/zwave-button.groovy @@ -23,10 +23,11 @@ metadata { capability "Health Check" capability "Configuration" - fingerprint mfr: "010F", prod: "0F01", model: "1000", deviceJoinName: "Fibaro Button" - fingerprint mfr: "010F", prod: "0F01", model: "2000", deviceJoinName: "Fibaro Button" - fingerprint mfr: "0371", prod: "0102", model: "0004", deviceJoinName: "Aeotec NanoMote One" //US - fingerprint mfr: "0371", prod: "0002", model: "0004", deviceJoinName: "Aeotec NanoMote One" //EU + fingerprint mfr: "010F", prod: "0F01", model: "1000", deviceJoinName: "Fibaro Button" //Fibaro Button + fingerprint mfr: "010F", prod: "0F01", model: "2000", deviceJoinName: "Fibaro Button" //Fibaro Button + fingerprint mfr: "010F", prod: "0F01", model: "3000", deviceJoinName: "Fibaro Button" //Fibaro Button + fingerprint mfr: "0371", prod: "0102", model: "0004", deviceJoinName: "Aeotec Button" //US //Aeotec NanoMote One + fingerprint mfr: "0371", prod: "0002", model: "0004", deviceJoinName: "Aeotec Button" //EU //Aeotec NanoMote One } tiles(scale: 2) { @@ -133,7 +134,7 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { } private secure(cmd) { - if(zwaveInfo.zw.endsWith("s")) { + if(zwaveInfo.zw.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() @@ -160,7 +161,7 @@ private isAeotec() { private getSupportedButtonValues() { if (isAeotec()) { - ["pushed", "held"] + ["pushed", "held", "down_hold"] } else { ["pushed", "held", "down_hold", "double", "pushed_3x", "pushed_4x", "pushed_5x"] } diff --git a/devicetypes/smartthings/zwave-controller.src/zwave-controller.groovy b/devicetypes/smartthings/zwave-controller.src/zwave-controller.groovy index 51bd1401505..5c4ef2cc1d8 100644 --- a/devicetypes/smartthings/zwave-controller.src/zwave-controller.groovy +++ b/devicetypes/smartthings/zwave-controller.src/zwave-controller.groovy @@ -100,7 +100,7 @@ private command(physicalgraph.zwave.Command cmd) { private getDeviceIsSecure() { if (zwaveInfo && zwaveInfo.zw) { - return zwaveInfo.zw.endsWith("s") + return zwaveInfo.zw.contains("s") } else { return state.sec ? true : false } diff --git a/devicetypes/smartthings/zwave-device-multichannel.src/zwave-device-multichannel.groovy b/devicetypes/smartthings/zwave-device-multichannel.src/zwave-device-multichannel.groovy index efe7f9fdfbd..a017e88a776 100644 --- a/devicetypes/smartthings/zwave-device-multichannel.src/zwave-device-multichannel.groovy +++ b/devicetypes/smartthings/zwave-device-multichannel.src/zwave-device-multichannel.groovy @@ -99,8 +99,7 @@ def installed() { try { String dni = "${device.deviceNetworkId}-ep${num}" addChildDevice(typeName, dni, device.hub.id, - [completedSetup: true, label: "${device.displayName} ${componentLabel}", - isComponent: true, componentName: "ch${num}", componentLabel: "${componentLabel}"]) + [completedSetup: true, label: "${device.displayName} ${componentLabel}", isComponent: false]) // enabledEndpoints << num.toString() log.debug "Endpoint $num ($desc) added as $componentLabel" } catch (e) { @@ -275,6 +274,14 @@ def zwaveEvent(physicalgraph.zwave.commands.associationgrpinfov1.AssociationGrou } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) if (encapsulatedCommand) { def formatCmd = ([cmd.commandClass, cmd.command] + cmd.parameter).collect{ String.format("%02X", it) }.join() @@ -427,3 +434,9 @@ private encap(cmd, endpoint) { private encapWithDelay(commands, endpoint, delay=200) { delayBetween(commands.collect{ encap(it, endpoint) }, delay) } + +def updated() { + childDevices.each { + if (it.device.isComponent) { it.save([isComponent: false, componentLabel: null, componentName: null]) } + } +} diff --git a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy index 5e3536dc550..2fe7eb248b6 100644 --- a/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-dimmer-switch-generic.src/zwave-dimmer-switch-generic.groovy @@ -22,31 +22,35 @@ metadata { capability "Sensor" capability "Light" - fingerprint inClusters: "0x26", deviceJoinName: "Z-Wave Dimmer" - fingerprint mfr: "001D", prod: "1902", deviceJoinName: "Z-Wave Dimmer" - fingerprint mfr: "001D", prod: "3301", model: "0001", deviceJoinName: "Leviton Dimmer Switch" - fingerprint mfr: "001D", prod: "3201", model: "0001", deviceJoinName: "Leviton Dimmer Switch" - fingerprint mfr: "001D", prod: "1B03", model: "0334", deviceJoinName: "Leviton Universal Dimmer" - fingerprint mfr: "011A", prod: "0102", model: "0201", deviceJoinName: "Enerwave In-Wall Dimmer" - fingerprint mfr: "001D", prod: "0602", model: "0334", deviceJoinName: "Leviton Magnetic Low Voltage Dimmer" - fingerprint mfr: "001D", prod: "0401", model: "0334", deviceJoinName: "Leviton 600W Incandescent Dimmer" - fingerprint mfr: "0111", prod: "8200", model: "0200", deviceJoinName: "Remotec Technology Plug-In Dimmer", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "1104", prod: "001D", model: "0501", deviceJoinName: "Leviton 1000W Incandescant Dimmer" - fingerprint mfr: "0039", prod: "5044", model: "3033", deviceJoinName: "Honeywell Z-Wave Plug-in Dimmer (Dual Outlet)", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0039", prod: "5044", model: "3038", deviceJoinName: "Honeywell Z-Wave Plug-in Dimmer", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0039", prod: "4944", model: "3038", deviceJoinName: "Honeywell Z-Wave In-Wall Smart Dimmer" - fingerprint mfr: "0039", prod: "4944", model: "3130", deviceJoinName: "Honeywell Z-Wave In-Wall Smart Toggle Dimmer" - fingerprint mfr: "001A", prod: "4449", model: "0101", deviceJoinName: "Eaton RF Master Dimmer" - fingerprint mfr: "001A", prod: "4449", model: "0003", deviceJoinName: "Eaton RF Dimming Plug-In Module", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "014F", prod: "5744", model: "3530", deviceJoinName: "GoControl In-Wall Dimmer" - fingerprint mfr: "0307", prod: "4447", model: "3034", deviceJoinName: "Satco In-Wall Dimmer" + fingerprint inClusters: "0x26", deviceJoinName: "Dimmer Switch" //Z-Wave Dimmer + fingerprint mfr: "001D", prod: "1902", deviceJoinName: "Dimmer Switch" //Z-Wave Dimmer + fingerprint mfr: "001D", prod: "3301", model: "0001", deviceJoinName: "Leviton Dimmer Switch" //Leviton Dimmer Switch + fingerprint mfr: "001D", prod: "3201", model: "0001", deviceJoinName: "Leviton Dimmer Switch" //Leviton Dimmer Switch + fingerprint mfr: "001D", prod: "1B03", model: "0334", deviceJoinName: "Leviton Dimmer Switch" //Leviton Universal Dimmer + fingerprint mfr: "011A", prod: "0102", model: "0201", deviceJoinName: "Enerwave Dimmer Switch" //Enerwave In-Wall Dimmer + fingerprint mfr: "001D", prod: "0602", model: "0334", deviceJoinName: "Leviton Dimmer Switch" //Leviton Magnetic Low Voltage Dimmer + fingerprint mfr: "001D", prod: "0401", model: "0334", deviceJoinName: "Leviton Dimmer Switch" //Leviton 600W Incandescent Dimmer + fingerprint mfr: "0111", prod: "8200", model: "0200", deviceJoinName: "Remotec Dimmer Switch", ocfDeviceType: "oic.d.smartplug" //Remotec Technology Plug-In Dimmer + fingerprint mfr: "1104", prod: "001D", model: "0501", deviceJoinName: "Leviton Dimmer Switch" //Leviton 1000W Incandescant Dimmer + fingerprint mfr: "0039", prod: "5044", model: "3033", deviceJoinName: "Honeywell Dimmer Switch", ocfDeviceType: "oic.d.smartplug" //Honeywell Z-Wave Plug-in Dimmer (Dual Outlet) + fingerprint mfr: "0039", prod: "5044", model: "3038", deviceJoinName: "Honeywell Dimmer Switch", ocfDeviceType: "oic.d.smartplug" //Honeywell Z-Wave Plug-in Dimmer + fingerprint mfr: "0039", prod: "4944", model: "3038", deviceJoinName: "Honeywell Dimmer Switch" //Honeywell Z-Wave In-Wall Smart Dimmer + fingerprint mfr: "0039", prod: "4944", model: "3130", deviceJoinName: "Honeywell Dimmer Switch" //Honeywell Z-Wave In-Wall Smart Toggle Dimmer + fingerprint mfr: "001A", prod: "4449", model: "0101", deviceJoinName: "Eaton Dimmer Switch" //Eaton RF Master Dimmer + fingerprint mfr: "001A", prod: "4449", model: "0003", deviceJoinName: "Eaton Dimmer Switch", ocfDeviceType: "oic.d.smartplug" //Eaton RF Dimming Plug-In Module + fingerprint mfr: "014F", prod: "5744", model: "3530", deviceJoinName: "GoControl Dimmer Switch" //GoControl In-Wall Dimmer + fingerprint mfr: "0307", prod: "4447", model: "3034", deviceJoinName: "Satco Dimmer Switch" //Satco In-Wall Dimmer //zw:L type:1101 mfr:0184 prod:4744 model:3032 ver:5.07 zwv:3.95 lib:03 cc:5E,86,72,5A,85,59,73,26,27,70,7A role:05 ff:8600 ui:8600 - fingerprint mfr: "0184", prod: "4744", model: "3032", deviceJoinName: "Satco Plug-In Dimmer", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0330", prod: "0201", model: "D002", deviceJoinName: "RGBgenie ZW-1001 Z-Wave Dimmer" - fingerprint mfr: "027A", prod: "B112", model: "1F1C", deviceJoinName: "Zooz ZEN22 Dimmer" - fingerprint mfr: "027A", prod: "A000", model: "A002", deviceJoinName: "Zooz ZEN27 Dimmer" - fingerprint mfr: "027A", prod: "B112", model: "261C", deviceJoinName: "Zooz ZEN24 Dimmer" - fingerprint mfr: "0300", prod: "0003", model: "0005", deviceJoinName: "ilumin Dimmable Bulb", ocfDeviceType: "oic.d.light" + fingerprint mfr: "0184", prod: "4744", model: "3032", deviceJoinName: "Satco Dimmer Switch", ocfDeviceType: "oic.d.smartplug" //Satco Plug-In Dimmer + fingerprint mfr: "0330", prod: "0201", model: "D002", deviceJoinName: "RGBgenie Dimmer Switch" //RGBgenie ZW-1001 Z-Wave Dimmer + fingerprint mfr: "027A", prod: "B112", model: "1F1C", deviceJoinName: "Zooz Dimmer Switch" //Zooz ZEN22 Dimmer + fingerprint mfr: "027A", prod: "A000", model: "A002", deviceJoinName: "Zooz Dimmer Switch" //Zooz ZEN27 Dimmer + fingerprint mfr: "027A", prod: "B112", model: "261C", deviceJoinName: "Zooz Dimmer Switch" //Zooz ZEN24 Dimmer + fingerprint mfr: "0300", prod: "0003", model: "0005", deviceJoinName: "ilumin Light", ocfDeviceType: "oic.d.light" //ilumin Dimmable Bulb + fingerprint mfr: "0312", prod: "FF00", model: "FF04", deviceJoinName: "Minoston Dimmer Switch" //Minoston Smart Dimmer Switch + fingerprint mfr: "0312", prod: "FF00", model: "FF02", deviceJoinName: "Minoston Dimmer Switch" //Minoston Toggle Dimmer Switch + fingerprint mfr: "0312", prod: "AA00", model: "AA02", deviceJoinName: "Evalogik Dimmer Switch" //Evalogik Smart Dimmer Switch + fingerprint mfr: "0312", prod: "C000", model: "C002", deviceJoinName: "Evalogik Dimmer Switch" //Evalogik Smart Plug Dimmer } simulator { @@ -140,7 +144,7 @@ def parse(String description) { result = zwaveEvent(cmd) } } - if (result?.name == 'hail' && hubFirmwareLessThan("000.011.00602")) { + if (result?.name?.equals('hail') && hubFirmwareLessThan("000.011.00602")) { result = [result, response(zwave.basicV1.basicGet())] log.debug "Was hailed: requesting state update" } else { @@ -272,4 +276,4 @@ def isHoneywellDimmer() { (zwaveInfo?.prod?.equals("4944") && zwaveInfo?.model?.equals("3038")) || (zwaveInfo?.prod?.equals("4944") && zwaveInfo?.model?.equals("3130")) ) -} +} \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-door-temp-sensor.src/i18n/messages.properties b/devicetypes/smartthings/zwave-door-temp-sensor.src/i18n/messages.properties new file mode 100644 index 00000000000..1a64327c7c5 --- /dev/null +++ b/devicetypes/smartthings/zwave-door-temp-sensor.src/i18n/messages.properties @@ -0,0 +1,112 @@ +# Copyright 2019 SmartThings +# +# 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. + +# Device Preferences +'''Select how many degrees to adjust the temperature.'''.en=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-gb=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-us=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.en-ca=Select how many degrees to adjust the temperature. +'''Select how many degrees to adjust the temperature.'''.sq=Përzgjidh sa gradë do ta rregullosh temperaturën. +'''Select how many degrees to adjust the temperature.'''.ar=حدد عدد الدرجات لتعديل درجة الحرارة. +'''Select how many degrees to adjust the temperature.'''.be=Выберыце, на колькі градусаў трэба адрэгуляваць тэмпературу. +'''Select how many degrees to adjust the temperature.'''.sr-ba=Izaberite za koliko stepeni želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.bg=Изберете на колко градуса да регулирате температурата. +'''Select how many degrees to adjust the temperature.'''.ca=Selecciona quants graus vols ajustar la temperatura. +'''Select how many degrees to adjust the temperature.'''.zh-cn=选择调整温度的度数。 +'''Select how many degrees to adjust the temperature.'''.zh-hk=選擇將溫度調整多少度。 +'''Select how many degrees to adjust the temperature.'''.zh-tw=選擇欲調整溫度的補正度數。 +'''Select how many degrees to adjust the temperature.'''.hr=Odaberite za koliko stupnjeva želite prilagoditi temperaturu. +'''Select how many degrees to adjust the temperature.'''.cs=Vyberte, o kolik stupňů se má teplota posunout. +'''Select how many degrees to adjust the temperature.'''.da=Vælg, hvor mange grader temperaturen skal justeres. +'''Select how many degrees to adjust the temperature.'''.nl=Selecteer met hoeveel graden de temperatuur moet worden aangepast. +'''Select how many degrees to adjust the temperature.'''.et=Valige, kui mitu kraadi, et reguleerida temperatuuri. +'''Select how many degrees to adjust the temperature.'''.fi=Valitse, kuinka monella asteella lämpötilaa säädetään. +'''Select how many degrees to adjust the temperature.'''.fr=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.fr-ca=Sélectionnez de combien de degrés la température doit être ajustée. +'''Select how many degrees to adjust the temperature.'''.de=Wählen Sie die Gradanzahl zum Anpassen der Temperatur aus. +'''Select how many degrees to adjust the temperature.'''.el=Επιλέξτε τους βαθμούς για τη ρύθμιση της θερμοκρασίας. +'''Select how many degrees to adjust the temperature.'''.iw=בחר בכמה מעלות להתאים את הטמפרטורה. +'''Select how many degrees to adjust the temperature.'''.hi-in=चुनें कि कितने डिग्री तक तापमान को समायोजित करना है। +'''Select how many degrees to adjust the temperature.'''.hu=Válassza ki, hogy hány fokra szeretné beállítani a hőmérsékletet. +'''Select how many degrees to adjust the temperature.'''.is=Veldu um hversu margar gráður á að stilla hitann. +'''Select how many degrees to adjust the temperature.'''.in=Pilih berapa derajat suhu akan disesuaikan. +'''Select how many degrees to adjust the temperature.'''.it=Selezionate il numero di gradi per regolare la temperatura. +'''Select how many degrees to adjust the temperature.'''.ja=温度を調整する度数を選択してください。 +'''Select how many degrees to adjust the temperature.'''.ko=측정 온도가 지속적으로 맞지 않을 경우, 온도를 보정해 주세요. +'''Select how many degrees to adjust the temperature.'''.lv=Izvēlieties, par cik grādiem regulēt temperatūru. +'''Select how many degrees to adjust the temperature.'''.lt=Pasirinkite, keliais laipsniais pakoreguoti temperatūrą. +'''Select how many degrees to adjust the temperature.'''.ms=Pilih tahap darjah untuk melaraskan suhu. +'''Select how many degrees to adjust the temperature.'''.no=Velg hvor mange grader du vil justere temperaturen. +'''Select how many degrees to adjust the temperature.'''.pl=Wybierz liczbę stopni, aby dostosować temperaturę. +'''Select how many degrees to adjust the temperature.'''.pt=Seleccionar quantos graus deve ser ajustada a temperatura. +'''Select how many degrees to adjust the temperature.'''.ro=Selectați cu câte grade doriți să ajustați temperatura. +'''Select how many degrees to adjust the temperature.'''.ru=Выберите, на сколько градусов изменить температуру. +'''Select how many degrees to adjust the temperature.'''.sr=Izaberite na koliko stepeni želite da podesite temperaturu. +'''Select how many degrees to adjust the temperature.'''.sk=Vyberte, o koľko stupňov sa má upraviť teplota. +'''Select how many degrees to adjust the temperature.'''.sl=Izberite, za koliko stopinj naj se prilagodi temperatura. +'''Select how many degrees to adjust the temperature.'''.es=Selecciona en cuántos grados quieres regular la temperatura. +'''Select how many degrees to adjust the temperature.'''.sv=Välj hur många grader som temperaturen ska justeras. +'''Select how many degrees to adjust the temperature.'''.th=เลือกองศาที่จะปรับอุณหภูมิ +'''Select how many degrees to adjust the temperature.'''.tr=Sıcaklığın kaç derece ayarlanacağını seçin. +'''Select how many degrees to adjust the temperature.'''.uk=Виберіть, на скільки градусів змінити температуру. +'''Select how many degrees to adjust the temperature.'''.vi=Chọn bao nhiêu độ để điều chỉnh nhiệt độ. +'''Temperature offset'''.en=Temperature offset +'''Temperature offset'''.en-gb=Temperature offset +'''Temperature offset'''.en-us=Temperature offset +'''Temperature offset'''.en-ca=Temperature offset +'''Temperature offset'''.sq=Shmangia e temperaturës +'''Temperature offset'''.ar=تعويض درجة الحرارة +'''Temperature offset'''.be=Карэкцыя тэмпературы +'''Temperature offset'''.sr-ba=Kompenzacija temperature +'''Temperature offset'''.bg=Компенсация на температурата +'''Temperature offset'''.ca=Compensació de temperatura +'''Temperature offset'''.zh-cn=温度偏差 +'''Temperature offset'''.zh-hk=溫度偏差 +'''Temperature offset'''.zh-tw=溫度偏差 +'''Temperature offset'''.hr=Kompenzacija temperature +'''Temperature offset'''.cs=Posun teploty +'''Temperature offset'''.da=Temperaturforskydning +'''Temperature offset'''.nl=Temperatuurverschil +'''Temperature offset'''.et=Temperatuuri nihkeväärtus +'''Temperature offset'''.fi=Lämpötilan siirtymä +'''Temperature offset'''.fr=Écart de température +'''Temperature offset'''.fr-ca=Écart de température +'''Temperature offset'''.de=Temperaturabweichung +'''Temperature offset'''.el=Αντιστάθμιση θερμοκρασίας +'''Temperature offset'''.iw=קיזוז טמפרטורה +'''Temperature offset'''.hi-in=तापमान की भरपाई +'''Temperature offset'''.hu=Hőmérsékletérték eltolása +'''Temperature offset'''.is=Vikmörk hitastigs +'''Temperature offset'''.in=Offset suhu +'''Temperature offset'''.it=Differenza temperatura +'''Temperature offset'''.ja=温度オフセット +'''Temperature offset'''.ko=온도 오프셋 +'''Temperature offset'''.lv=Temperatūras nobīde +'''Temperature offset'''.lt=Temperatūros skirtumas +'''Temperature offset'''.ms=Ofset suhu +'''Temperature offset'''.no=Temperaturforskyvning +'''Temperature offset'''.pl=Różnica temperatury +'''Temperature offset'''.pt=Diferença de temperatura +'''Temperature offset'''.ro=Decalaj temperatură +'''Temperature offset'''.ru=Поправка температуры +'''Temperature offset'''.sr=Odstupanje temperature +'''Temperature offset'''.sk=Posun teploty +'''Temperature offset'''.sl=Temperaturni odmik +'''Temperature offset'''.es=Compensación de temperatura +'''Temperature offset'''.sv=Temperaturavvikelse +'''Temperature offset'''.th=การชดเชยอุณหภูมิ +'''Temperature offset'''.tr=Sıcaklık ofseti +'''Temperature offset'''.uk=Поправка температури +'''Temperature offset'''.vi=Độ lệch nhiệt độ +# End of Device Preferences diff --git a/devicetypes/smartthings/zwave-door-temp-sensor.src/zwave-door-temp-sensor.groovy b/devicetypes/smartthings/zwave-door-temp-sensor.src/zwave-door-temp-sensor.groovy index 6dcc0ea8886..79f12250846 100644 --- a/devicetypes/smartthings/zwave-door-temp-sensor.src/zwave-door-temp-sensor.groovy +++ b/devicetypes/smartthings/zwave-door-temp-sensor.src/zwave-door-temp-sensor.groovy @@ -23,16 +23,16 @@ metadata { capability "Health Check" capability "Temperature Measurement" - fingerprint mfr:"015D", prod:"2003", model:"B41C", deviceJoinName: "Inovelli Door/Temp Sensor" - fingerprint mfr:"0312", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Door/Temp Sensor" - fingerprint mfr:"015D", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Door/Temp Sensor" - fingerprint mfr:"015D", prod:"C100", model:"C100", deviceJoinName: "Inovelli Door/Temp Sensor" - fingerprint mfr:"0312", prod:"C100", model:"C100", deviceJoinName: "Inovelli Door/Temp Sensor" + fingerprint mfr:"015D", prod:"2003", model:"B41C", deviceJoinName: "Inovelli Open/Closed Sensor" //Inovelli Door/Temp Sensor + fingerprint mfr:"0312", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Open/Closed Sensor" //Inovelli Door/Temp Sensor + fingerprint mfr:"015D", prod:"2003", model:"C11C", deviceJoinName: "Inovelli Open/Closed Sensor" //Inovelli Door/Temp Sensor + fingerprint mfr:"015D", prod:"C100", model:"C100", deviceJoinName: "Inovelli Open/Closed Sensor" //Inovelli Door/Temp Sensor + fingerprint mfr:"0312", prod:"C100", model:"C100", deviceJoinName: "Inovelli Open/Closed Sensor" //Inovelli Door/Temp Sensor } preferences { section { - input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false + input "tempOffset", "number", title: "Temperature offset", description: "Select how many degrees to adjust the temperature.", range: "-100..100", displayDuringSetup: false } } diff --git a/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy b/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy index 12b3fe81672..1e73e6afc22 100644 --- a/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy +++ b/devicetypes/smartthings/zwave-door-window-sensor.src/zwave-door-window-sensor.groovy @@ -23,40 +23,45 @@ metadata { capability "Battery" capability "Configuration" capability "Health Check" + capability "Tamper Alert" - fingerprint deviceId: "0x2001", inClusters: "0x30,0x80,0x84,0x85,0x86,0x72" - fingerprint deviceId: "0x07", inClusters: "0x30" - fingerprint deviceId: "0x0701", inClusters: "0x5E,0x98" - fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82" - fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters: "0x20" + fingerprint deviceId: "0x2001", inClusters: "0x30,0x80,0x84,0x85,0x86,0x72", deviceJoinName: "Open/Closed Sensor" + fingerprint deviceId: "0x07", inClusters: "0x30", deviceJoinName: "Open/Closed Sensor" + fingerprint deviceId: "0x0701", inClusters: "0x5E,0x98", deviceJoinName: "Open/Closed Sensor" + fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82", deviceJoinName: "Open/Closed Sensor" + fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters: "0x20", deviceJoinName: "Open/Closed Sensor" // Philio multi+ - fingerprint mfr: "0086", prod: "0002", model: "001D", deviceJoinName: "Aeotec Door/Window Sensor (Gen 5)" - fingerprint mfr: "0086", prod: "0102", model: "0070", deviceJoinName: "Aeotec Door/Window Sensor 6" //US - fingerprint mfr: "0086", prod: "0002", model: "0070", deviceJoinName: "Aeotec Door/Window Sensor 6" //EU - fingerprint mfr: "0086", prod: "0202", model: "0070", deviceJoinName: "Aeotec Door/Window Sensor 6" //AU - fingerprint mfr: "0086", prod: "0102", model: "0059", deviceJoinName: "Aeotec Recessed Door Sensor" - fingerprint mfr: "014A", prod: "0001", model: "0002", deviceJoinName: "Ecolink Door/Window Sensor" - fingerprint mfr: "014A", prod: "0001", model: "0003", deviceJoinName: "Ecolink Tilt Sensor" - fingerprint mfr: "014A", prod: "0004", model: "0003", deviceJoinName: "Ecolink Tilt Sensor" - fingerprint mfr: "011A", prod: "0601", model: "0903", deviceJoinName: "Enerwave Magnetic Door/Window Sensor" - fingerprint mfr: "014F", prod: "2001", model: "0102", deviceJoinName: "Nortek GoControl Door/Window Sensor" - fingerprint mfr: "0063", prod: "4953", model: "3031", deviceJoinName: "Jasco Hinge Pin Door Sensor" - fingerprint mfr: "019A", prod: "0003", model: "0003", deviceJoinName: "Sensative Strips" - fingerprint mfr: "0258", prod: "0003", model: "0082", deviceJoinName: "NEO Coolcam Door/Window Sensor" - fingerprint mfr: "0258", prod: "0003", model: "1082", deviceJoinName: "NEO Coolcam Door/Window Sensor" // NAS-DS01ZE - fingerprint mfr: "021F", prod: "0003", model: "0101", deviceJoinName: "Dome Door/Window Sensor" + fingerprint mfr: "0086", prod: "0002", model: "001D", deviceJoinName: "Aeotec Open/Closed Sensor" //Aeotec Door/Window Sensor (Gen 5) + fingerprint mfr: "0086", prod: "0102", model: "0070", deviceJoinName: "Aeotec Open/Closed Sensor" //US //Aeotec Door/Window Sensor 6 + fingerprint mfr: "0086", prod: "0002", model: "0070", deviceJoinName: "Aeotec Open/Closed Sensor" //EU //Aeotec Door/Window Sensor 6 + fingerprint mfr: "0086", prod: "0202", model: "0070", deviceJoinName: "Aeotec Open/Closed Sensor" //AU //Aeotec Door/Window Sensor 6 + fingerprint mfr: "0086", prod: "0102", model: "0059", deviceJoinName: "Aeotec Open/Closed Sensor" //Aeotec Recessed Door Sensor + fingerprint mfr: "014A", prod: "0001", model: "0002", deviceJoinName: "Ecolink Open/Closed Sensor" //Ecolink Door/Window Sensor + fingerprint mfr: "014A", prod: "0001", model: "0003", deviceJoinName: "Ecolink Open/Closed Sensor" //Ecolink Tilt Sensor + fingerprint mfr: "014A", prod: "0004", model: "0003", deviceJoinName: "Ecolink Open/Closed Sensor" //Ecolink Tilt Sensor + fingerprint mfr: "011A", prod: "0601", model: "0903", deviceJoinName: "Enerwave Open/Closed Sensor" //Enerwave Magnetic Door/Window Sensor + fingerprint mfr: "014F", prod: "2001", model: "0102", deviceJoinName: "Nortek Open/Closed Sensor" //Nortek GoControl Door/Window Sensor + fingerprint mfr: "0063", prod: "4953", model: "3031", deviceJoinName: "Jasco Open/Closed Sensor" //Jasco Hinge Pin Door Sensor + fingerprint mfr: "019A", prod: "0003", model: "0003", deviceJoinName: "Sensative Open/Closed Sensor" //Sensative Strips + fingerprint mfr: "0258", prod: "0003", model: "0082", deviceJoinName: "NEO Coolcam Open/Closed Sensor" //NEO Coolcam Door/Window Sensor + fingerprint mfr: "0258", prod: "0003", model: "1082", deviceJoinName: "NEO Coolcam Open/Closed Sensor" // NAS-DS01ZE //NEO Coolcam Door/Window Sensor + fingerprint mfr: "021F", prod: "0003", model: "0101", deviceJoinName: "Dome Open/Closed Sensor" //Dome Door/Window Sensor //zw:S type:0701 mfr:014A prod:0004 model:0002 ver:10.01 zwv:4.05 lib:06 cc:5E,86,72,73,80,71,85,59,84,30,70 ccOut:20 role:06 ff:8C07 ui:8C00 - fingerprint mfr: "014A", prod: "0004", model: "0002", deviceJoinName: "Ecolink Door/Window Sensor" + fingerprint mfr: "014A", prod: "0004", model: "0002", deviceJoinName: "Ecolink Open/Closed Sensor" //Ecolink Door/Window Sensor //zw:Ss type:0701 mfr:0086 prod:0002 model:0059 ver:1.14 zwv:3.92 lib:03 cc:5E,86,72,98,5A ccOut:82 sec:30,80,84,70,85,59,71,7A,73 role:06 ff:8C00 ui:8C00 - fingerprint mfr: "0086", prod: "0002", model: "0059", deviceJoinName: "Aeon Recessed Door Sensor" + fingerprint mfr: "0086", prod: "0002", model: "0059", deviceJoinName: "Aeon Open/Closed Sensor" //Aeon Recessed Door Sensor //zw:S type:0701 mfr:0214 prod:0002 model:0001 ver:6.38 zwv:4.38 lib:06 cc:5E,30,84,80,86,72,71,70,85,59,73,5A role:06 ff:8C06 ui:8C06 - fingerprint mfr: "0214", prod: "0002", model: "0001", deviceJoinName: "BeSense Door/Window Detector" - fingerprint mfr: "0086", prod: "0002", model: "0078", deviceJoinName: "Aeotec Door/Window Sensor Gen5" //EU - fingerprint mfr: "0371", prod: "0102", model: "0007", deviceJoinName: "Aeotec Door/Window Sensor 7" //EU - fingerprint mfr: "0371", prod: "0002", model: "0007", deviceJoinName: "Aeotec Door/Window Sensor 7" //US - fingerprint mfr: "0060", prod: "0002", model: "0003", deviceJoinName: "Everspring Door/Window Sensor" //US & EU - fingerprint mfr: "0371", prod: "0102", model: "00BB", deviceJoinName: "Aeotec Recessed Door Sensor 7" //US - fingerprint mfr: "0371", prod: "0002", model: "00BB", deviceJoinName: "Aeotec Recessed Door Sensor 7" //EU + fingerprint mfr: "0214", prod: "0002", model: "0001", deviceJoinName: "BeSense Open/Closed Sensor" //BeSense Door/Window Detector + fingerprint mfr: "0086", prod: "0002", model: "0078", deviceJoinName: "Aeotec Open/Closed Sensor" //EU //Aeotec Door/Window Sensor Gen5 + fingerprint mfr: "0371", prod: "0102", model: "0007", deviceJoinName: "Aeotec Open/Closed Sensor" //EU //Aeotec Door/Window Sensor 7 + fingerprint mfr: "0371", prod: "0002", model: "0007", deviceJoinName: "Aeotec Open/Closed Sensor" //US //Aeotec Door/Window Sensor 7 + fingerprint mfr: "0060", prod: "0002", model: "0003", deviceJoinName: "Everspring Open/Closed Sensor" //US & EU //Everspring Door/Window Sensor + fingerprint mfr: "0371", prod: "0102", model: "00BB", deviceJoinName: "Aeotec Open/Closed Sensor" //US //Aeotec Recessed Door Sensor 7 + fingerprint mfr: "0371", prod: "0002", model: "00BB", deviceJoinName: "Aeotec Open/Closed Sensor" //EU //Aeotec Recessed Door Sensor 7 + fingerprint mfr: "0109", prod: "2022", model: "2201", deviceJoinName: "Vision Open/Closed Sensor" //AU //Vision Recessed Door Sensor + fingerprint mfr: "0371", prod: "0002", model: "000C", deviceJoinName: "Aeotec Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-5" //EU //Aeotec Door/Window Sensor 7 Pro + fingerprint mfr: "0371", prod: "0102", model: "000C", deviceJoinName: "Aeotec Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-5" //US //Aeotec Door/Window Sensor 7 Pro + fingerprint mfr: "0371", prod: "0202", model: "000C", deviceJoinName: "Aeotec Open/Closed Sensor", mnmn: "SmartThings", vid: "generic-contact-5" //AU //Aeotec Door/Window Sensor 7 Pro } // simulator metadata @@ -91,7 +96,7 @@ private getCommandClassVersions() { def parse(String description) { def result = null if (description.startsWith("Err 106")) { - if ((zwaveInfo.zw == null && state.sec != 0) || zwaveInfo?.zw?.endsWith("s")) { + if ((zwaveInfo.zw == null && state.sec != 0) || zwaveInfo?.zw?.contains("s")) { log.debug description } else { result = createEvent( @@ -118,6 +123,7 @@ def installed() { // this is the nuclear option because the device often goes to sleep before we can poll it sendEvent(name: "contact", value: "open", descriptionText: "$device.displayName is open") sendEvent(name: "battery", unit: "%", value: 100) + sendEvent(name: "tamper", value: "clear") response(initialPoll()) } @@ -127,7 +133,11 @@ def updated() { } def configure() { - // currently supported devices do not require initial configuration + //Recessed Door Sensor 7 - Enable Binary Sensor Report for S2 Authenticated + if (zwaveInfo.mfr == "0371" || zwaveInfo.model == "00BB") { + result << response(command(zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, scaledConfigurationValue: 1))) + result + } } def sensorValueEvent(value) { @@ -167,10 +177,13 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm } else if (cmd.notificationType == 0x07) { if (cmd.v1AlarmType == 0x07) { // special case for nonstandard messages from Monoprice door/window sensors result << sensorValueEvent(cmd.v1AlarmLevel) + } else if (cmd.event == 0x00) { + result << createEvent(name: "tamper", value: "clear") } else if (cmd.event == 0x01 || cmd.event == 0x02) { result << sensorValueEvent(1) } else if (cmd.event == 0x03) { - result << createEvent(descriptionText: "$device.displayName covering was removed", isStateChange: true) + runIn(10, clearTamper, [overwrite: true, forceForLocallyExecuting: true]) + result << createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was tampered") if (!state.MSR) result << response(command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())) } else if (cmd.event == 0x05 || cmd.event == 0x06) { result << createEvent(descriptionText: "$device.displayName detected glass breakage", isStateChange: true) @@ -275,6 +288,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { def result = null + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) log.debug "Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}" if (encapsulatedCommand) { @@ -308,7 +329,7 @@ def initialPoll() { } private command(physicalgraph.zwave.Command cmd) { - if ((zwaveInfo.zw == null && state.sec != 0) || zwaveInfo?.zw?.endsWith("s")) { + if ((zwaveInfo?.zw == null && state.sec != 0) || zwaveInfo?.zw?.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() @@ -358,3 +379,7 @@ def retypeBasedOnMSR() { private isEnerwave() { zwaveInfo?.mfr?.equals("011A") && zwaveInfo?.prod?.equals("0601") && zwaveInfo?.model?.equals("0901") } + +def clearTamper() { + sendEvent(name: "tamper", value: "clear") +} diff --git a/devicetypes/smartthings/zwave-dual-switch.src/zwave-dual-switch.groovy b/devicetypes/smartthings/zwave-dual-switch.src/zwave-dual-switch.groovy index 4b70e456a1b..18abf6efd0e 100644 --- a/devicetypes/smartthings/zwave-dual-switch.src/zwave-dual-switch.groovy +++ b/devicetypes/smartthings/zwave-dual-switch.src/zwave-dual-switch.groovy @@ -22,13 +22,15 @@ metadata { // This DTH uses 2 switch endpoints. Parent DTH controls endpoint 1 so please use '1' at the end of deviceJoinName // Child device (isComponent : false) representing endpoint 2 will substitute 1 with 2 for easier identification. - fingerprint mfr: "0086", prod: "0103", model: "008C", deviceJoinName: "Aeotec Dual Nano Switch 1" //US - fingerprint mfr: "0086", prod: "0003", model: "008C", deviceJoinName: "Aeotec Dual Nano Switch 1" //EU + fingerprint mfr: "0086", prod: "0103", model: "008C", deviceJoinName: "Aeotec Switch 1" //US //Aeotec Dual Nano Switch 1 + fingerprint mfr: "0086", prod: "0003", model: "008C", deviceJoinName: "Aeotec Switch 1" //EU //Aeotec Dual Nano Switch 1 // sometimes the aeotec nano dual switch does not update its NIF when adding securely - fingerprint mfr: "0000", cc: "0x5E,0x25,0x27,0x81,0x71,0x60,0x8E,0x2C,0x2B,0x70,0x86,0x72,0x73,0x85,0x59,0x98,0x7A,0x5A", ccOut: "0x82", ui: "0x8700", deviceJoinName: "Aeotec Dual Nano Switch 1" - fingerprint mfr: "0258", prod: "0003", model: "008B", deviceJoinName: "NEO Coolcam Light Switch 1" - fingerprint mfr: "0258", prod: "0003", model: "108B", deviceJoinName: "NEO coolcam Light Switch 1" - fingerprint mfr: "0312", prod: "C000", model: "C004", deviceJoinName: "EVA LOGIK Smart Plug 2CH 1" + fingerprint mfr: "0000", cc: "0x5E,0x25,0x27,0x81,0x71,0x60,0x8E,0x2C,0x2B,0x70,0x86,0x72,0x73,0x85,0x59,0x98,0x7A,0x5A", ccOut: "0x82", ui: "0x8700", deviceJoinName: "Aeotec Switch 1" //Aeotec Dual Nano Switch 1 + fingerprint mfr: "0258", prod: "0003", model: "008B", deviceJoinName: "NEO Coolcam Switch 1" //NEO Coolcam Light Switch 1 + fingerprint mfr: "0258", prod: "0003", model: "108B", deviceJoinName: "NEO Coolcam Switch 1" //NEO coolcam Light Switch 1 + fingerprint mfr: "0312", prod: "C000", model: "C004", deviceJoinName: "EVA Switch 1" //EVA LOGIK Smart Plug 2CH 1 + fingerprint mfr: "0312", prod: "FF00", model: "FF05", deviceJoinName: "Minoston Switch 1" //Minoston Smart Plug 2CH 1 + fingerprint mfr: "0312", prod: "C000", model: "C007", deviceJoinName: "Evalogik Switch 1" //Evalogik Outdoor Smart Plug 2CH 1 } // tile definitions @@ -140,6 +142,14 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1]) if (cmd.sourceEndPoint == 1) { zwaveEvent(encapsulatedCommand, 1) @@ -221,7 +231,7 @@ def encap(endpointNumber, cmd) { private command(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s")) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { cmd.format() @@ -234,4 +244,4 @@ private secEncap(physicalgraph.zwave.Command cmd) { private crcEncap(physicalgraph.zwave.Command cmd) { zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format() -} +} \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy b/devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy index 096141a36df..c040aa06620 100644 --- a/devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy +++ b/devicetypes/smartthings/zwave-fan-controller.src/zwave-fan-controller.groovy @@ -27,10 +27,11 @@ metadata { command "raiseFanSpeed" command "lowerFanSpeed" - fingerprint mfr: "001D", prod: "1001", model: "0334", deviceJoinName: "Leviton 3-Speed Fan Controller" - fingerprint mfr: "0063", prod: "4944", model: "3034", deviceJoinName: "GE In-Wall Smart Fan Control" - fingerprint mfr: "0063", prod: "4944", model: "3131", deviceJoinName: "GE In-Wall Smart Fan Control" - fingerprint mfr: "0039", prod: "4944", model: "3131", deviceJoinName: "Honeywell Z-Wave Plus In-Wall Fan Speed Control" + fingerprint mfr: "001D", prod: "0038", model: "0002", deviceJoinName: "Leviton Fan", mnmn: "SmartThings", vid: "SmartThings-smartthings-Z-Wave_Fan_Controller_4_Speed" //Leviton 4-Speed Fan Controller + fingerprint mfr: "001D", prod: "1001", model: "0334", deviceJoinName: "Leviton Fan" //Leviton 3-Speed Fan Controller + fingerprint mfr: "0063", prod: "4944", model: "3034", deviceJoinName: "GE Fan" //GE In-Wall Smart Fan Control + fingerprint mfr: "0063", prod: "4944", model: "3131", deviceJoinName: "GE Fan" //GE In-Wall Smart Fan Control + fingerprint mfr: "0039", prod: "4944", model: "3131", deviceJoinName: "Honeywell Fan" //Honeywell Z-Wave Plus In-Wall Fan Speed Control } simulator { @@ -123,13 +124,10 @@ def fanEvents(physicalgraph.zwave.Command cmd) { def fanLevel = 0 - // The GE, Honeywell, and Leviton treat 33 as medium, so account for that - if (1 <= rawLevel && rawLevel <= 32) { - fanLevel = 1 - } else if (33 <= rawLevel && rawLevel <= 66) { - fanLevel = 2 - } else if (67 <= rawLevel && rawLevel <= 100) { - fanLevel = 3 + if (has4Speeds()) { + fanLevel = getFanSpeedFor4SpeedDevice(rawLevel) + } else { + fanLevel = getFanSpeedFor3SpeedDevice(rawLevel) } result << createEvent(name: "fanSpeed", value: fanLevel) } @@ -188,6 +186,8 @@ def setFanSpeed(speed) { medium() } else if (speed as Integer == 3) { high() + } else if (speed as Integer == 4) { + max() } } @@ -200,14 +200,18 @@ def lowerFanSpeed() { } def low() { - setLevel(32) + setLevel(has4Speeds() ? 25 : 32) } def medium() { - setLevel(66) + setLevel(has4Speeds() ? 50 : 66) } def high() { + setLevel(has4Speeds() ? 75 : 99) +} + +def max() { setLevel(99) } @@ -217,4 +221,39 @@ def refresh() { def ping() { refresh() +} + +def getFanSpeedFor3SpeedDevice(rawLevel) { + // The GE, Honeywell, and Leviton 3-Speed Fan Controller treat 33 as medium, so account for that + if (rawLevel == 0) { + return 0 + } else if (1 <= rawLevel && rawLevel <= 32) { + return 1 + } else if (33 <= rawLevel && rawLevel <= 66) { + return 2 + } else if (67 <= rawLevel && rawLevel <= 100) { + return 3 + } +} + +def getFanSpeedFor4SpeedDevice(rawLevel) { + if (rawLevel == 0) { + return 0 + } else if (1 <= rawLevel && rawLevel <= 25) { + return 1 + } else if (26 <= rawLevel && rawLevel <= 50) { + return 2 + } else if (51 <= rawLevel && rawLevel <= 75) { + return 3 + } else if (76 <= rawLevel && rawLevel <= 100) { + return 4 + } +} + +def has4Speeds() { + isLeviton4Speed() +} + +def isLeviton4Speed() { + (zwaveInfo?.mfr == "001D" && zwaveInfo?.prod == "0038" && zwaveInfo?.model == "0002") } \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-garage-door-opener.src/zwave-garage-door-opener.groovy b/devicetypes/smartthings/zwave-garage-door-opener.src/zwave-garage-door-opener.groovy index 7dd8b32f234..f8fab8f0827 100644 --- a/devicetypes/smartthings/zwave-garage-door-opener.src/zwave-garage-door-opener.groovy +++ b/devicetypes/smartthings/zwave-garage-door-opener.src/zwave-garage-door-opener.groovy @@ -23,11 +23,11 @@ metadata { capability "Refresh" capability "Sensor" - fingerprint inClusters: "0x66, 0x98, 0x71, 0x72" - fingerprint deviceId: "0x4007", inClusters: "0x98" - fingerprint deviceId: "0x4006", inClusters: "0x98" - fingerprint mfr:"014F", prod:"4744", model:"3030", deviceJoinName: "Linear GoControl Garage Door Opener" - fingerprint mfr:"014F", prod:"4744", model:"3530", deviceJoinName: "GoControl Smart Garage Door Controller" + fingerprint inClusters: "0x66, 0x98, 0x71, 0x72", deviceJoinName: "Garage Door" + fingerprint deviceId: "0x4007", inClusters: "0x98", deviceJoinName: "Garage Door" + fingerprint deviceId: "0x4006", inClusters: "0x98", deviceJoinName: "Garage Door" + fingerprint mfr:"014F", prod:"4744", model:"3030", deviceJoinName: "Linear Garage Door" //Linear GoControl Garage Door Opener + fingerprint mfr:"014F", prod:"4744", model:"3530", deviceJoinName: "GoControl Garage Door" //GoControl Smart Garage Door Controller } simulator { diff --git a/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy b/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy index 8ab6472749e..8e338181460 100644 --- a/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy +++ b/devicetypes/smartthings/zwave-lock-without-codes.src/zwave-lock-without-codes.groovy @@ -23,11 +23,14 @@ metadata { capability "Health Check" capability "Configuration" - fingerprint inClusters: "0x62" - fingerprint mfr: "010E", prod: "0009", model: "0001", deviceJoinName: "Danalock V3 Smart Lock" - fingerprint mfr: "0090", prod: "0003", model: "0446", deviceJoinName: "Kwikset Convert Deadbolt Door Lock" //99140 - fingerprint mfr: "033F", prod: "0001", model: "0001", deviceJoinName: "August Smart Lock Pro" - fingerprint mfr: "021D", prod: "0003", model: "0001", deviceJoinName: "Alfred Smart Home Touchscreen Deadbolt" // DB2 + fingerprint inClusters: "0x62", deviceJoinName: "Door Lock" + fingerprint mfr: "010E", prod: "0009", model: "0001", deviceJoinName: "Danalock Door Lock" //Danalock V3 Smart Lock + fingerprint mfr: "0090", prod: "0003", model: "0446", deviceJoinName: "Kwikset Door Lock" //99140 //Kwikset Convert Deadbolt Door Lock + fingerprint mfr: "033F", prod: "0001", model: "0001", deviceJoinName: "August Door Lock" //August Smart Lock Pro + fingerprint mfr: "021D", prod: "0003", model: "0001", deviceJoinName: "Alfred Door Lock" // DB2 //Alfred Smart Home Touchscreen Deadbolt + //zw:Fs type:4001 mfr:0154 prod:0005 model:0001 ver:1.05 zwv:4.38 lib:03 cc:7A,73,80,5A,98 sec:5E,86,72,30,71,70,59,85,62 + fingerprint mfr: "0154", prod: "0005", model: "0001", deviceJoinName: "POPP Door Lock" // POPP Strike Lock Control POPE012501 + fingerprint mfr: "003B", prod: "0001", model: "0469", deviceJoinName: "Schlage Door Lock" //BE469ZP //Schlage Connect Smart Deadbolt Door Lock } simulator { @@ -95,7 +98,7 @@ def installed() { * and check again. */ def scheduleInstalledCheck() { - runIn(120, installedCheck, [forceForLocallyExecuting: true]) + runIn(120, "installedCheck", [forceForLocallyExecuting: true]) } def installedCheck() { @@ -405,6 +408,12 @@ private def handleBatteryAlarmReport(cmd) { def deviceName = device.displayName def map = null switch (cmd.zwaveAlarmEvent) { + case 0x01: //power has been applied, check if the battery level updated + log.debug "Batteries replaced. Queueing a battery get." + runIn(10, "queryBattery", [overwrite: true, forceForLocallyExecuting: true]) + state.batteryQueries = 0 + result << response(secure(zwave.batteryV1.batteryGet())) + break; case 0x0A: map = [name: "battery", value: 1, descriptionText: "Battery level critical", displayed: true, data: [lockName: deviceName]] break @@ -419,6 +428,102 @@ private def handleBatteryAlarmReport(cmd) { result } +/** + * Responsible for handling AlarmReport commands which are ignored by Access & Burglar handlers + * + * @param cmd: The AlarmReport command to be parsed + * + * @return The event(s) to be sent out + * + */ +private def handleAlarmReportUsingAlarmType(cmd) { + log.trace "[DTH] Executing 'handleAlarmReportUsingAlarmType' with cmd = $cmd" + def result = [] + def map = null + def deviceName = device.displayName + switch(cmd.alarmType) { + case 9: + case 17: + map = [ name: "lock", value: "unknown", descriptionText: "Unknown state" ] + break + case 16: // Note: for levers this means it's unlocked, for non-motorized deadbolt, it's just unsecured and might not get unlocked + case 19: // Unlocked with keypad + map = [ name: "lock", value: "unlocked" , method: "keypad"] + map.descriptionText = "Unlocked by keypad" + break + case 18: // Locked with keypad + codeID = readCodeSlotId(cmd) + map = [ name: "lock", value: "locked" ] + map.descriptionText = "Locked by keypad" + map.data = [ method: "keypad" ] + break + case 21: // Manually locked + map = [ name: "lock", value: "locked", data: [ method: (cmd.alarmLevel == 2) ? "keypad" : "manual" ] ] + map.descriptionText = "Locked manually" + break + case 22: // Manually unlocked + map = [ name: "lock", value: "unlocked", data: [ method: "manual" ] ] + map.descriptionText = "Unlocked manually" + break + case 23: + map = [ name: "lock", value: "unknown", descriptionText: "Unknown state" ] + map.data = [ method: "command" ] + break + case 24: // Locked by command + map = [ name: "lock", value: "locked", data: [ method: "command" ] ] + map.descriptionText = "Locked" + break + case 25: // Unlocked by command + map = [ name: "lock", value: "unlocked", data: [ method: "command" ] ] + map.descriptionText = "Unlocked" + break + case 26: + map = [ name: "lock", value: "unknown", descriptionText: "Unknown state" ] + map.data = [ method: "auto" ] + break + case 27: // Auto locked + map = [ name: "lock", value: "locked", data: [ method: "auto" ] ] + map.descriptionText = "Auto locked" + break + case 130: // Batteries replaced + map = [ descriptionText: "Batteries replaced", isStateChange: true ] + break + case 161: // Tamper Alarm + if (cmd.alarmLevel == 2) { + map = [ name: "tamper", value: "detected", descriptionText: "Front escutcheon removed", isStateChange: true ] + } + break + case 167: // Low Battery Alarm + if (!state.lastbatt || now() - state.lastbatt > 12*60*60*1000) { + map = [ descriptionText: "Battery low", isStateChange: true ] + result << response(secure(zwave.batteryV1.batteryGet())) + } else { + map = [ name: "battery", value: device.currentValue("battery"), descriptionText: "Battery low", isStateChange: true ] + } + break + case 168: // Critical Battery Alarms + map = [ name: "battery", value: 1, descriptionText: "Battery level critical", displayed: true ] + break + case 169: // Battery too low to operate + map = [ name: "battery", value: 0, descriptionText: "Battery too low to operate lock", isStateChange: true, displayed: true ] + break + default: + map = [ displayed: false, descriptionText: "Alarm event ${cmd.alarmType} level ${cmd.alarmLevel}" ] + break + } + + if (map) { + if (map.data) { + map.data.lockName = deviceName + } else { + map.data = [ lockName: deviceName ] + } + result << createEvent(map) + } + result = result.flatten() + result +} + /** * Responsible for parsing BatteryReport command * @@ -438,6 +543,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { map.value = cmd.batteryLevel } state.lastbatt = now() + unschedule("queryBattery") if (cmd.batteryLevel == 0 && device.latestValue("battery") > 20) { // Danalock reports 00 when batteries are changed. We do not know what is the real level at this point. // We will ignore this level to mimic normal operation of the device (battery level is refreshed only when motor is operating) @@ -510,7 +616,7 @@ def unlockWithTimeout() { */ def ping() { log.trace "[DTH] Executing ping() for device ${device.displayName}" - runIn(30, followupStateCheck) + runIn(30, "followupStateCheck") if (zwaveInfo.mfr == "010E") { secure(zwave.doorLockV1.doorLockOperationGet()) } else { @@ -589,3 +695,14 @@ private Boolean secondsPast(timestamp, seconds) { return (now() - timestamp) > (seconds * 1000) } +private queryBattery() { + log.debug "Running queryBattery" + if (state.batteryQueries == null) state.batteryQueries = 0 + if ((!state.lastbatt || now() - state.lastbatt > 10*1000) && state.batteryQueries < 5) { + log.debug "It's been more than 10s since battery was updated after a replacement. Querying battery." + runIn(10, "queryBattery", [overwrite: true, forceForLocallyExecuting: true]) + state.batteryQueries = state.batteryQueries + 1 + sendHubCommand(secure(zwave.batteryV1.batteryGet())) + } +} + diff --git a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy index 10d06b137aa..33faffb9fc1 100644 --- a/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy +++ b/devicetypes/smartthings/zwave-lock.src/zwave-lock.groovy @@ -26,50 +26,52 @@ metadata { capability "Configuration" // Generic - fingerprint inClusters: "0x62, 0x63" - fingerprint deviceId: "0x4003", inClusters: "0x98" - fingerprint deviceId: "0x4004", inClusters: "0x98" + fingerprint inClusters: "0x62, 0x63", deviceJoinName: "Door Lock" + fingerprint deviceId: "0x4003", inClusters: "0x98", deviceJoinName: "Door Lock" + fingerprint deviceId: "0x4004", inClusters: "0x98", deviceJoinName: "Door Lock" // KwikSet - fingerprint mfr:"0090", prod:"0001", model:"0236", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock" - fingerprint mfr:"0090", prod:"0003", model:"0238", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock" - fingerprint mfr:"0090", prod:"0001", model:"0001", deviceJoinName: "KwikSet SmartCode 910 Contemporary Deadbolt Door Lock" - fingerprint mfr:"0090", prod:"0003", model:"0339", deviceJoinName: "KwikSet SmartCode 912 Lever Door Lock" - fingerprint mfr:"0090", prod:"0003", model:"4006", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock" //backlit version - fingerprint mfr:"0090", prod:"0003", model:"0440", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock" - fingerprint mfr:"0090", prod:"0001", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock" - fingerprint mfr:"0090", prod:"0003", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock" + fingerprint mfr:"0090", prod:"0001", model:"0236", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 910 Deadbolt Door Lock + fingerprint mfr:"0090", prod:"0003", model:"0238", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 910 Deadbolt Door Lock + fingerprint mfr:"0090", prod:"0001", model:"0001", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 910 Contemporary Deadbolt Door Lock + fingerprint mfr:"0090", prod:"0003", model:"0339", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 912 Lever Door Lock + fingerprint mfr:"0090", prod:"0003", model:"4006", deviceJoinName: "KwikSet Door Lock" //backlit version //KwikSet SmartCode 914 Deadbolt Door Lock + fingerprint mfr:"0090", prod:"0003", model:"0440", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 914 Deadbolt Door Lock + fingerprint mfr:"0090", prod:"0001", model:"0642", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock + fingerprint mfr:"0090", prod:"0003", model:"0642", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock //zw:Fs type:4003 mfr:0090 prod:0003 model:0541 ver:4.79 zwv:4.34 lib:03 cc:5E,72,5A,98,73,7A sec:86,80,62,63,85,59,71,70,5D role:07 ff:8300 ui:8300 - fingerprint mfr:"0090", prod:"0003", model:"0541", deviceJoinName: "KwikSet SmartCode 888 Touchpad Deadbolt Door Lock" + fingerprint mfr:"0090", prod:"0003", model:"0541", deviceJoinName: "KwikSet Door Lock" //KwikSet SmartCode 888 Touchpad Deadbolt Door Lock //zw:Fs type:4003 mfr:0090 prod:0003 model:0742 ver:4.10 zwv:4.34 lib:03 cc:5E,72,5A,98,73,7A sec:86,80,62,63,85,59,71,70,4E,8B,4C,5D role:07 ff:8300 ui:8300 - fingerprint mfr:"0090", prod:"0003", model:"0742", deviceJoinName: "Kwikset Obsidian Lock" + fingerprint mfr:"0090", prod:"0003", model:"0742", deviceJoinName: "Kwikset Door Lock" //Kwikset Obsidian Lock // Schlage - fingerprint mfr:"003B", prod:"6341", model:"0544", deviceJoinName: "Schlage Touchscreen Deadbolt Door Lock" - fingerprint mfr:"003B", prod:"6341", model:"5044", deviceJoinName: "Schlage Touchscreen Deadbolt Door Lock" - fingerprint mfr:"003B", prod:"634B", model:"504C", deviceJoinName: "Schlage Connected Keypad Lever Door Lock" - fingerprint mfr:"003B", prod:"0001", model:"0468", deviceJoinName: "Schlage Connect Smart Deadbolt Door Lock" //BE468ZP - fingerprint mfr:"003B", prod:"0001", model:"0469", deviceJoinName: "Schlage Connect Smart Deadbolt Door Lock" //BE469ZP + fingerprint mfr:"003B", prod:"6341", model:"0544", deviceJoinName: "Schlage Door Lock" //Schlage Touchscreen Deadbolt Door Lock + fingerprint mfr:"003B", prod:"6341", model:"5044", deviceJoinName: "Schlage Door Lock" //Schlage Touchscreen Deadbolt Door Lock + fingerprint mfr:"003B", prod:"634B", model:"504C", deviceJoinName: "Schlage Door Lock" //Schlage Connected Keypad Lever Door Lock + fingerprint mfr:"003B", prod:"0001", model:"0468", deviceJoinName: "Schlage Door Lock" //BE468ZP //Schlage Connect Smart Deadbolt Door Lock + fingerprint mfr:"003B", prod:"0004", model:"2109", deviceJoinName: "Schlage Door Lock" //Schlage Keypad Deadbolt JBE109 + fingerprint mfr:"003B", prod:"0004", model:"6109", deviceJoinName: "Schlage Door Lock" //Schlage Keypad Lever JFE109 // Yale - fingerprint mfr:"0129", prod:"0002", model:"0800", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD120 - fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD220, YRD240 - fingerprint mfr:"0129", prod:"0002", model:"FFFF", deviceJoinName: "Yale Touchscreen Lever Door Lock" // YRD220 - fingerprint mfr:"0129", prod:"0004", model:"0800", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD110 - fingerprint mfr:"0129", prod:"0004", model:"0000", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD210 - fingerprint mfr:"0129", prod:"0001", model:"0000", deviceJoinName: "Yale Push Button Lever Door Lock" // YRD210 - fingerprint mfr:"0129", prod:"8002", model:"0600", deviceJoinName: "Yale Assure Lock" //YRD416, YRD426, YRD446 - fingerprint mfr:"0129", prod:"0007", model:"0001", deviceJoinName: "Yale Keyless Connected Smart Door Lock" - fingerprint mfr:"0129", prod:"8004", model:"0600", deviceJoinName: "Yale Assure Lock Push Button Deadbolt" //YRD216 - fingerprint mfr:"0129", prod:"6600", model:"0002", deviceJoinName: "Yale Conexis Lock" - fingerprint mfr:"0129", prod:"0001", model:"0409", deviceJoinName: "Yale Touchscreen Lever Door Lock" // YRL-220-ZW-605 - fingerprint mfr:"0129", prod:"800B", model:"0F00", deviceJoinName: "Yale Assure Keypad Lever Door Lock" // YRL216-ZW2 - fingerprint mfr:"0129", prod:"800C", model:"0F00", deviceJoinName: "Yale Assure Touchscreen Lever Door Lock" // YRL226-ZW2 - fingerprint mfr:"0129", prod:"8002", model:"1000", deviceJoinName: "Yale Assure Lock" //YRD-ZWM-1 + fingerprint mfr:"0129", prod:"0002", model:"0800", deviceJoinName: "Yale Door Lock" // YRD120 //Yale Touchscreen Deadbolt Door Lock + fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Door Lock" // YRD220, YRD240 //Yale Touchscreen Deadbolt Door Lock + fingerprint mfr:"0129", prod:"0002", model:"FFFF", deviceJoinName: "Yale Door Lock" // YRD220 //Yale Touchscreen Lever Door Lock + fingerprint mfr:"0129", prod:"0004", model:"0800", deviceJoinName: "Yale Door Lock" // YRD110 //Yale Push Button Deadbolt Door Lock + fingerprint mfr:"0129", prod:"0004", model:"0000", deviceJoinName: "Yale Door Lock" // YRD210 //Yale Push Button Deadbolt Door Lock + fingerprint mfr:"0129", prod:"0001", model:"0000", deviceJoinName: "Yale Door Lock" // YRD210 //Yale Push Button Lever Door Lock + fingerprint mfr:"0129", prod:"8002", model:"0600", deviceJoinName: "Yale Door Lock" //YRD416, YRD426, YRD446 //Yale Assure Lock + fingerprint mfr:"0129", prod:"0007", model:"0001", deviceJoinName: "Yale Door Lock" //Yale Keyless Connected Smart Door Lock + fingerprint mfr:"0129", prod:"8004", model:"0600", deviceJoinName: "Yale Door Lock" //YRD216 //Yale Assure Lock Push Button Deadbolt + fingerprint mfr:"0129", prod:"6600", model:"0002", deviceJoinName: "Yale Door Lock" //Yale Conexis Lock + fingerprint mfr:"0129", prod:"0001", model:"0409", deviceJoinName: "Yale Door Lock" // YRL-220-ZW-605 //Yale Touchscreen Lever Door Lock + fingerprint mfr:"0129", prod:"800B", model:"0F00", deviceJoinName: "Yale Door Lock" // YRL216-ZW2. YRL236 //Yale Assure Keypad Lever Door Lock + fingerprint mfr:"0129", prod:"800C", model:"0F00", deviceJoinName: "Yale Door Lock" // YRL226-ZW2 //Yale Assure Touchscreen Lever Door Lock + fingerprint mfr:"0129", prod:"8002", model:"1000", deviceJoinName: "Yale Door Lock" //YRD-ZWM-1 //Yale Assure Lock + fingerprint mfr:"0129", prod:"803A", model:"0508", deviceJoinName: "Yale Door Lock" //YRD156 //Yale Touchscreen Deadbolt with Integrated ZWave Plus // Samsung - fingerprint mfr:"022E", prod:"0001", model:"0001", deviceJoinName: "Samsung Digital Lock", mnmn: "SmartThings", vid: "SmartThings-smartthings-Samsung_Smart_Doorlock" // SHP-DS705, SHP-DHP728, SHP-DHP525 + fingerprint mfr:"022E", prod:"0001", model:"0001", deviceJoinName: "Samsung Door Lock", mnmn: "SmartThings", vid: "SmartThings-smartthings-Samsung_Smart_Doorlock" // SHP-DS705, SHP-DHP728, SHP-DHP525 //Samsung Digital Lock // KeyWe - fingerprint mfr:"037B", prod:"0002", model:"0001", deviceJoinName: "KeyWe Lock" // GKW-2000D - fingerprint mfr:"037B", prod:"0003", model:"0001", deviceJoinName: "KeyWe Smart Rim Lock" // GKW-1000Z + fingerprint mfr:"037B", prod:"0002", model:"0001", deviceJoinName: "KeyWe Door Lock" // GKW-2000D //KeyWe Lock + fingerprint mfr:"037B", prod:"0003", model:"0001", deviceJoinName: "KeyWe Door Lock" // GKW-1000Z //KeyWe Smart Rim Lock // Philia - fingerprint mfr:"0366", prod:"0001", model:"0001", deviceJoinName: "Philia Smart Door Lock" // PDS-100 + fingerprint mfr:"0366", prod:"0001", model:"0001", deviceJoinName: "Philia Door Lock" // PDS-100 //Philia Smart Door Lock } simulator { @@ -132,7 +134,7 @@ def installed() { * and check again. */ def scheduleInstalledCheck() { - runIn(120, installedCheck, [forceForLocallyExecuting: true]) + runIn(120, "installedCheck", [forceForLocallyExecuting: true]) } def installedCheck() { @@ -630,6 +632,9 @@ private def handleBatteryAlarmReport(cmd) { def map = null switch(cmd.zwaveAlarmEvent) { case 0x01: //power has been applied, check if the battery level updated + log.debug "Batteries replaced. Queueing a battery get." + runIn(10, "queryBattery", [overwrite: true, forceForLocallyExecuting: true]) + state.batteryQueries = 0 result << response(secure(zwave.batteryV1.batteryGet())) break; case 0x0A: @@ -767,6 +772,10 @@ private def handleAlarmReportUsingAlarmType(cmd) { break case 130: // Batteries replaced map = [ descriptionText: "Batteries replaced", isStateChange: true ] + log.debug "Batteries replaced. Queueing a battery check." + runIn(10, "queryBattery", [overwrite: true, forceForLocallyExecuting: true]) + state.batteryQueries = 0 + result << response(secure(zwave.batteryV1.batteryGet())) break case 131: // Disabled user entered at keypad map = [ descriptionText: "Code ${cmd.alarmLevel} is disabled", isStateChange: false ] @@ -1035,6 +1044,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { map.descriptionText = "Battery is at ${cmd.batteryLevel}%" } state.lastbatt = now() + unschedule("queryBattery") createEvent(map) } @@ -1155,7 +1165,7 @@ def unlockWithTimeout() { */ def ping() { log.trace "[DTH] Executing ping() for device ${device.displayName}" - runIn(30, followupStateCheck) + runIn(30, "followupStateCheck") secure(zwave.doorLockV1.doorLockOperationGet()) } @@ -1797,3 +1807,14 @@ def readCodeSlotId(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) { } return cmd.alarmLevel } + +private queryBattery() { + log.debug "Running queryBattery" + if (state.batteryQueries == null) state.batteryQueries = 0 + if ((!state.lastbatt || now() - state.lastbatt > 10*1000) && state.batteryQueries < 5) { + log.debug "It's been more than 10s since battery was updated after a replacement. Querying battery." + runIn(10, "queryBattery", [overwrite: true, forceForLocallyExecuting: true]) + state.batteryQueries = state.batteryQueries + 1 + sendHubCommand(secure(zwave.batteryV1.batteryGet())) + } +} diff --git a/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy b/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy index 926c3414b72..e0b876a7b8b 100644 --- a/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy +++ b/devicetypes/smartthings/zwave-metering-dimmer.src/zwave-metering-dimmer.groovy @@ -31,15 +31,15 @@ metadata { command "reset" - fingerprint inClusters: "0x26,0x32" - fingerprint mfr:"0086", prod:"0003", model:"001B", deviceJoinName: "Aeotec Micro Smart Dimmer 2E" - fingerprint mfr:"0086", prod:"0103", model:"0063", deviceJoinName: "Aeotec Smart Dimmer 6" //US - fingerprint mfr:"0086", prod:"0003", model:"0063", deviceJoinName: "Aeotec Smart Dimmer 6" //EU - fingerprint mfr:"0086", prod:"0103", model:"006F", deviceJoinName: "Aeotec Nano Dimmer" - fingerprint mfr:"0086", prod:"0003", model:"006F", deviceJoinName: "Aeotec Nano Dimmer" - fingerprint mfr:"0086", prod:"0203", model:"006F", deviceJoinName: "Aeotec Nano Dimmer" //AU - fingerprint mfr:"014F", prod:"5044", model:"3533", deviceJoinName: "GoControl Plug-in Dimmer" - fingerprint mfr:"0159", prod:"0001", model:"0055", deviceJoinName: "Qubino Mini Dimmer ZMNHHD1" + fingerprint inClusters: "0x26,0x32", deviceJoinName: "Dimmer Switch" + fingerprint mfr:"0086", prod:"0003", model:"001B", deviceJoinName: "Aeotec Dimmer Switch" //Aeotec Micro Smart Dimmer 2E + fingerprint mfr:"0086", prod:"0103", model:"0063", deviceJoinName: "Aeotec Dimmer Switch" //US //Aeotec Smart Dimmer 6 + fingerprint mfr:"0086", prod:"0003", model:"0063", deviceJoinName: "Aeotec Dimmer Switch" //EU //Aeotec Smart Dimmer 6 + fingerprint mfr:"0086", prod:"0103", model:"006F", deviceJoinName: "Aeotec Dimmer Switch" //Aeotec Nano Dimmer + fingerprint mfr:"0086", prod:"0003", model:"006F", deviceJoinName: "Aeotec Dimmer Switch" //Aeotec Nano Dimmer + fingerprint mfr:"0086", prod:"0203", model:"006F", deviceJoinName: "Aeotec Dimmer Switch" //AU //Aeotec Nano Dimmer + fingerprint mfr:"014F", prod:"5044", model:"3533", deviceJoinName: "GoControl Dimmer Switch" //GoControl Plug-in Dimmer + fingerprint mfr:"0159", prod:"0001", model:"0055", deviceJoinName: "Qubino Dimmer Switch" //Qubino Mini Dimmer ZMNHHD1 } simulator { @@ -93,6 +93,24 @@ metadata { main(["switch","power","energy"]) details(["switch", "power", "energy", "refresh", "reset"]) + + preferences { + section { + input( + title: "Settings Available For Aeotec Nano Dimmer Only", + type: "paragraph", + element: "paragraph" + ) + input( + title: "Set the MIN brightness level (Aeotec Nano Dimmer Only):", + description: "This may need to be adjusted for bulbs that are not dimming properly.", + name: "minDimmingLevel", + type: "number", + range: "1..99", + defaultValue: 1 + ) + } + } } def getCommandClassVersions() { @@ -113,7 +131,15 @@ def installed() { def updated() { // Device-Watch simply pings if no device events received for 32min(checkInterval) sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - response(refresh()) + + def results = [] + results << refresh() + + if (isAeotecNanoDimmer()) { + results << getAeotecNanoDimmerConfigurationCommands() + } + + response(results) } // parse events into attributes @@ -228,8 +254,14 @@ def setLevel(level, rate = null) { def configure() { log.debug "configure()" + def result = [] + if (isAeotecNanoDimmer()) { + state.configured = false + result << response(getAeotecNanoDimmerConfigurationCommands()) + } + log.debug "Configure zwaveInfo: "+zwaveInfo if (zwaveInfo.mfr == "0086") { // Aeon Labs meter @@ -269,6 +301,36 @@ def normalizeLevel(level) { level == 99 ? 100 : level } +def getAeotecNanoDimmerConfigurationCommands() { + def result = [] + Integer minDimmingLevel = (settings.minDimmingLevel as Integer) ?: 1 // default value (parameter 131) for Aeotec Nano Dimmer + + if (!state.minDimmingLevel) { + state.minDimmingLevel = 1 // default value (parameter 131) for Aeotec Nano Dimmer + } + + if (!state.configured || (minDimmingLevel != state.minDimmingLevel)) { + state.configured = false // this flag needs to be set to false when settings are changed (and the device was initially configured before) + result << encap(zwave.configurationV1.configurationSet(parameterNumber: 131, size: 1, scaledConfigurationValue: minDimmingLevel)) + result << encap(zwave.configurationV1.configurationGet(parameterNumber: 131)) + } + + return result +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) { + if (isAeotecNanoDimmer()) { + if (cmd.parameterNumber == 131) { + state.minDimmingLevel = cmd.scaledConfigurationValue + state.configured = true + } + + log.debug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd.configurationValue}'" + } + + return [:] +} + /* * Security encapsulation support: */ @@ -318,3 +380,7 @@ private encap(physicalgraph.zwave.Command cmd) { private encapSequence(cmds, Integer delay=250) { delayBetween(cmds.collect{ encap(it) }, delay) } + +private isAeotecNanoDimmer() { + zwaveInfo?.mfr?.equals("0086") && zwaveInfo?.model?.equals("006F") +} diff --git a/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy b/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy index f750dbb9c81..6d6d9309b2e 100644 --- a/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy +++ b/devicetypes/smartthings/zwave-metering-switch-secure.src/zwave-metering-switch-secure.groovy @@ -25,8 +25,8 @@ metadata { command "reset" - fingerprint deviceId: "0x1001", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x32, 0x8E, 0x71, 0x73, 0x98, 0x31, 0x25, 0x86", outClusters: "" - fingerprint mfr: "0072", prod: "0501", model: "0F06", deviceJoinName: "Fibaro Wall Plug ZW5" // US + fingerprint deviceId: "0x1001", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x32, 0x8E, 0x71, 0x73, 0x98, 0x31, 0x25, 0x86", outClusters: "", deviceJoinName: "Outlet" + fingerprint mfr: "0072", prod: "0501", model: "0F06", deviceJoinName: "Fibaro Outlet" // US //Fibaro Wall Plug ZW5 } // simulator metadata diff --git a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy index 74d04cb3a9f..d0ba1e97b0b 100644 --- a/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-metering-switch.src/zwave-metering-switch.groovy @@ -25,32 +25,33 @@ metadata { command "reset" - fingerprint inClusters: "0x25,0x32" - fingerprint mfr: "0086", prod: "0003", model: "0012", deviceJoinName: "Aeotec Micro Smart Switch" - fingerprint mfr: "021F", prod: "0003", model: "0087", deviceJoinName: "Dome On/Off Plug-in Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0086", prod: "0103", model: "0060", deviceJoinName: "Aeotec Smart Switch 6", ocfDeviceType: "oic.d.smartplug" //US - fingerprint mfr: "0086", prod: "0003", model: "0060", deviceJoinName: "Aeotec Smart Switch 6", ocfDeviceType: "oic.d.smartplug" //EU - fingerprint mfr: "0086", prod: "0203", model: "0060", deviceJoinName: "Aeotec Smart Switch 6", ocfDeviceType: "oic.d.smartplug" //AU - fingerprint mfr: "0086", prod: "0103", model: "0074", deviceJoinName: "Aeotec Nano Switch" - fingerprint mfr: "0086", prod: "0003", model: "0074", deviceJoinName: "Aeotec Nano Switch" - fingerprint mfr: "0086", prod: "0203", model: "0074", deviceJoinName: "Aeotec Nano Switch" //AU - fingerprint mfr: "014F", prod: "574F", model: "3535", deviceJoinName: "GoControl Wall-Mounted Outlet", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "014F", prod: "5053", model: "3531", deviceJoinName: "GoControl Plug-in Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0063", prod: "4F44", model: "3031", deviceJoinName: "GE Direct-Wire Outdoor Switch" - fingerprint mfr: "0258", prod: "0003", model: "0087", deviceJoinName: "NEO Coolcam Power plug", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "010F", prod: "0602", model: "1001", deviceJoinName: "Fibaro Wall Plug ZW5", ocfDeviceType: "oic.d.smartplug" // EU - fingerprint mfr: "010F", prod: "1801", model: "1000", deviceJoinName: "Fibaro Wall Plug ZW5", ocfDeviceType: "oic.d.smartplug"// UK - fingerprint mfr: "0086", prod: "0003", model: "004E", deviceJoinName: "Aeotec Heavy Duty Smart Switch" //EU - fingerprint mfr: "0086", prod: "0103", model: "004E", deviceJoinName: "Aeotec Heavy Duty Smart Switch" //US + fingerprint inClusters: "0x25,0x32", deviceJoinName: "Switch" + fingerprint mfr: "0086", prod: "0003", model: "0012", deviceJoinName: "Aeotec Switch" //Aeotec Micro Smart Switch + fingerprint mfr: "021F", prod: "0003", model: "0087", deviceJoinName: "Dome Outlet", ocfDeviceType: "oic.d.smartplug" //Dome On/Off Plug-in Switch + fingerprint mfr: "0086", prod: "0103", model: "0060", deviceJoinName: "Aeotec Outlet", ocfDeviceType: "oic.d.smartplug" //US //Aeotec Smart Switch 6 + fingerprint mfr: "0086", prod: "0003", model: "0060", deviceJoinName: "Aeotec Outlet", ocfDeviceType: "oic.d.smartplug" //EU //Aeotec Smart Switch 6 + fingerprint mfr: "0086", prod: "0203", model: "0060", deviceJoinName: "Aeotec Outlet", ocfDeviceType: "oic.d.smartplug" //AU //Aeotec Smart Switch 6 + fingerprint mfr: "0086", prod: "0103", model: "0074", deviceJoinName: "Aeotec Switch" //Aeotec Nano Switch + fingerprint mfr: "0086", prod: "0003", model: "0074", deviceJoinName: "Aeotec Switch" //Aeotec Nano Switch + fingerprint mfr: "0086", prod: "0203", model: "0074", deviceJoinName: "Aeotec Switch" //AU //Aeotec Nano Switch + fingerprint mfr: "014F", prod: "574F", model: "3535", deviceJoinName: "GoControl Outlet", ocfDeviceType: "oic.d.smartplug" //GoControl Wall-Mounted Outlet + fingerprint mfr: "014F", prod: "5053", model: "3531", deviceJoinName: "GoControl Outlet", ocfDeviceType: "oic.d.smartplug" //GoControl Plug-in Switch + fingerprint mfr: "0063", prod: "4F44", model: "3031", deviceJoinName: "GE Switch" //GE Direct-Wire Outdoor Switch + fingerprint mfr: "0258", prod: "0003", model: "0087", deviceJoinName: "NEO Coolcam Outlet", ocfDeviceType: "oic.d.smartplug" //NEO Coolcam Power plug + fingerprint mfr: "010F", prod: "0602", model: "1001", deviceJoinName: "Fibaro Outlet", ocfDeviceType: "oic.d.smartplug" // EU //Fibaro Wall Plug ZW5 + fingerprint mfr: "010F", prod: "1801", model: "1000", deviceJoinName: "Fibaro Outlet", ocfDeviceType: "oic.d.smartplug"// UK //Fibaro Wall Plug ZW5 + fingerprint mfr: "0086", prod: "0003", model: "004E", deviceJoinName: "Aeotec Switch" //EU //Aeotec Heavy Duty Smart Switch + fingerprint mfr: "0086", prod: "0103", model: "004E", deviceJoinName: "Aeotec Switch" //US //Aeotec Heavy Duty Smart Switch //zw:L type:1001 mfr:0258 prod:0003 model:1087 ver:3.94 zwv:4.05 lib:03 cc:5E,72,86,85,59,5A,73,70,25,27,71,32,20 role:05 ff:8700 ui:8700 - fingerprint mfr: "0258", prod: "0003", model: "1087", deviceJoinName: "NEO Coolcam Power Plug", ocfDeviceType: "oic.d.smartplug" //EU - fingerprint mfr: "027A", prod: "0101", model: "000D", deviceJoinName: "Zooz Power Switch" - fingerprint mfr: "0159", prod: "0002", model: "0054", deviceJoinName: "Qubino Smart Plug", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0371", prod: "0003", model: "00AF", deviceJoinName: "Aeotec Smart Switch 7", ocfDeviceType: "oic.d.smartplug" //EU - fingerprint mfr: "0371", prod: "0103", model: "00AF", deviceJoinName: "Aeotec Smart Switch 7", ocfDeviceType: "oic.d.smartplug" //US - fingerprint mfr: "0060", prod: "0004", model: "000B", deviceJoinName: "Everspring Smart Plug", ocfDeviceType: "oic.d.smartplug" //US - fingerprint mfr: "031E", prod: "0002", model: "0001", deviceJoinName: "Inovelli Switch Red Series" //US - fingerprint mfr: "0154", prod: "0003", model: "000A", deviceJoinName: "POPP Smart Outdoor Plug" //EU + fingerprint mfr: "0258", prod: "0003", model: "1087", deviceJoinName: "NEO Coolcam Outlet", ocfDeviceType: "oic.d.smartplug" //EU //NEO Coolcam Power Plug + fingerprint mfr: "027A", prod: "0101", model: "000D", deviceJoinName: "Zooz Switch" //Zooz Power Switch + fingerprint mfr: "0159", prod: "0002", model: "0054", deviceJoinName: "Qubino Outlet", ocfDeviceType: "oic.d.smartplug" //Qubino Smart Plug + fingerprint mfr: "0371", prod: "0003", model: "00AF", deviceJoinName: "Aeotec Outlet", ocfDeviceType: "oic.d.smartplug" //EU //Aeotec Smart Switch 7 + fingerprint mfr: "0371", prod: "0103", model: "00AF", deviceJoinName: "Aeotec Outlet", ocfDeviceType: "oic.d.smartplug" //US //Aeotec Smart Switch 7 + fingerprint mfr: "0060", prod: "0004", model: "000B", deviceJoinName: "Everspring Outlet", ocfDeviceType: "oic.d.smartplug" //US //Everspring Smart Plug + fingerprint mfr: "031E", prod: "0002", model: "0001", deviceJoinName: "Inovelli Switch" //US //Inovelli Switch Red Series + fingerprint mfr: "0154", prod: "0003", model: "000A", deviceJoinName: "POPP Outlet", ocfDeviceType: "oic.d.smartplug" //EU //POPP Smart Outdoor Plug + fingerprint mfr: "010F", prod: "1F01", model: "1000", deviceJoinName: "Fibaro Outlet", ocfDeviceType: "oic.d.smartplug" //EU //Fibaro walli Outlet //Fibaro Outlet } // simulator metadata @@ -258,6 +259,8 @@ def configure() { result << response(encap(zwave.configurationV1.configurationSet(parameterNumber: 13, size: 2, scaledConfigurationValue: 5*60))) // report every 5 minutes } else if (zwaveInfo.mfr == "014F" && zwaveInfo.prod == "5053" && zwaveInfo.model == "3531") { result << response(encap(zwave.configurationV1.configurationSet(parameterNumber: 13, size: 2, scaledConfigurationValue: 15))) //report kWH every 15 min + } else if (zwaveInfo.mfr == "0154" && zwaveInfo.prod == "0003" && zwaveInfo.model == "000A") { + result << response(encap(zwave.configurationV1.configurationSet(parameterNumber: 25, size: 1, scaledConfigurationValue: 1))) //report every 1W change } result << response(encap(meterGet(scale: 0))) result << response(encap(meterGet(scale: 2))) diff --git a/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy b/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy index 26ed7d77b2a..e17f6f69651 100644 --- a/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy +++ b/devicetypes/smartthings/zwave-motion-light-sensor.src/zwave-motion-light-sensor.groovy @@ -17,7 +17,7 @@ */ metadata { - definition(name: "Z-Wave Motion/Light Sensor", namespace: "smartthings", author: "SmartThings") { + definition(name: "Z-Wave Motion/Light Sensor", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.motion") { capability "Motion Sensor" capability "Illuminance Measurement" capability "Battery" @@ -26,11 +26,12 @@ metadata { capability "Configuration" //zw:S type:0701 mfr:021F prod:0003 model:0083 ver:3.92 zwv:4.05 lib:06 cc:5E,86,72,5A,73,80,31,71,30,70,85,59,84 role:06 ff:8C07 ui:8C07 - fingerprint mfr: "021F", prod: "0003", model: "0083", deviceJoinName: "Dome Motion/Light Sensor" + fingerprint mfr: "021F", prod: "0003", model: "0083", deviceJoinName: "Dome Motion/Light Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-Dome_Motion_Light_Sensor_DMMS1" //zw:S type:0701 mfr:0258 prod:0003 model:008D ver:3.80 zwv:4.38 lib:06 cc:5E,86,72,5A,73,80,31,71,30,70,85,59,84 role:06 ff:8C07 ui:8C07 - fingerprint mfr: "0258", prod: "0003", model: "008D", deviceJoinName: "NEO Coolcam Motion/Light Sensor" + fingerprint mfr: "0258", prod: "0003", model: "008D", deviceJoinName: "NEO Coolcam Motion/Light Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-NEO_Coolcam_Motion_Light_Sensor" //zw:S type:0701 mfr:0258 prod:0003 model:108D ver:3.80 zwv:4.38 lib:06 cc:5E,86,72,5A,73,80,31,71,30,70,85,59,84 role:06 ff:8C07 ui:8C07 EU version - fingerprint mfr: "0258", prod: "0003", model: "108D", deviceJoinName: "NEO Coolcam Motion/Light Sensor" + fingerprint mfr: "0258", prod: "0003", model: "108D", deviceJoinName: "NEO Coolcam Motion/Light Sensor", mnmn: "SmartThings", vid: "SmartThings-smartthings-NEO_Coolcam_Motion_Light_Sensor" + fingerprint mfr: "017F", prod: "0101", model: "0001", deviceJoinName: "Wink Motion Sensor" } simulator { @@ -87,23 +88,12 @@ def updated() { } def configure() { - // Device wakes up every deviceCheckInterval hours, this interval allows us to miss one wakeup notification before marking offline - sendEvent(name: "checkInterval", value: 2 * deviceWakeUpInterval * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) -} - -def getDeviceWakeUpInterval() { - def deviceWakeIntervalValue = 4 - switch (zwaveInfo?.mfr) { - case "021F": - deviceWakeIntervalValue = 12 // Dome reports once in 12h - break - case "0258": - deviceWakeIntervalValue = 12 // NEO Coolcam reports once in 12h - break - default: - deviceWakeIntervalValue = 4 // Default Z-Wave battery device reports once in 4h + // Device wakes up every 8 hours (+ 2 minutes), this interval allows us to miss one wakeup notification before marking offline + sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Setting wakeUpNotification interval for NEO Coolcam and Dome devices + if (isNeoCoolcam() || isDome()) { + zwave.wakeUpV2.wakeUpIntervalSet(seconds: 4 * 3600, nodeid: zwaveHubNodeId).format() } - return deviceWakeIntervalValue } private getCommandClassVersions() { @@ -212,3 +202,10 @@ def sensorMotionEvent(value) { } return result } + +private isDome() { + zwaveInfo.mfr == "021F" && zwaveInfo.model == "0083" +} +private isNeoCoolcam() { + zwaveInfo.mfr == "0258" && (zwaveInfo.model == "108D" || zwaveInfo.model == "008D") +} diff --git a/devicetypes/smartthings/zwave-motion-light.src/zwave-motion-light.groovy b/devicetypes/smartthings/zwave-motion-light.src/zwave-motion-light.groovy index a493d983363..e927965985c 100644 --- a/devicetypes/smartthings/zwave-motion-light.src/zwave-motion-light.groovy +++ b/devicetypes/smartthings/zwave-motion-light.src/zwave-motion-light.groovy @@ -1,5 +1,5 @@ /** - * Copyright 2018 SmartThings + * Copyright 2019 SmartThings * * 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: @@ -16,12 +16,11 @@ metadata { definition(name: "Z-Wave Motion Light", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light", mmnm: "SmartThings", vid: "generic-motion-light") { capability "Switch" capability "Motion Sensor" - capability "Illuminance Measurement" capability "Sensor" capability "Health Check" capability "Configuration" - fingerprint mfr: "0060", prod: "0012", model: "0001", deviceJoinName: "Everspring Outdoor Floodlight" + fingerprint mfr: "0060", prod: "0012", model: "0001", deviceJoinName: "Everspring Light" //Everspring Outdoor Floodlight } tiles(scale: 2) { @@ -37,20 +36,9 @@ metadata { state("active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC") state("inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#CCCCCC") } - valueTile("illuminance", "device.illuminance", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { - state "illuminance", label: '${currentValue} lux', backgroundColors: [ - [value: 40, color: "#999900"], - [value: 100, color: "#CCCC00"], - [value: 300, color: "#FFFF00"], - [value: 500, color: "#FFFF33"], - [value: 1000, color: "#FFFF66"], - [value: 2000, color: "#FFFF99"], - [value: 10000, color: "#FFFFCC"] - ] - } main "switch" - details(["switch", "motion", "illuminance"]) + details(["switch", "motion"]) } } @@ -68,15 +56,10 @@ def updated() { } def configure() { - def cmds = [ - secure(zwave.notificationV3.notificationGet(notificationType: 0x07)), - secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03)), - secure(zwave.switchBinaryV1.switchBinaryGet()) + [ + secure(zwave.notificationV3.notificationGet(notificationType: 0x07)), + secure(zwave.switchBinaryV1.switchBinaryGet()) ] - if (isEverspringFloodlight()) { - cmds += secure(zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 10)) //enables illuminance report every 10 minutes - } - cmds } def ping() { @@ -132,29 +115,14 @@ def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cm def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { if (cmd.notificationType == 0x07) { - if (cmd.event == 0x08) { // detected + if (cmd.event == 0x08) { // detected createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion") - } else if (cmd.event == 0x00) { // inactive + } else if (cmd.event == 0x00) { // inactive createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped") } } } -def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { - def map = [:] - switch (cmd.sensorType) { - case 3: - map.name = "illuminance" - map.value = cmd.scaledSensorValue.toInteger().toString() - map.unit = "lux" - map.isStateChange = true - break - default: - map.descriptionText = cmd.toString() - } - createEvent(map) -} - def zwaveEvent(physicalgraph.zwave.Command cmd) { log.debug "Unhandled command: ${cmd}" [:] diff --git a/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy b/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy index d9d6538f71b..272c762440b 100644 --- a/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy +++ b/devicetypes/smartthings/zwave-motion-sensor.src/zwave-motion-sensor.groovy @@ -17,25 +17,39 @@ */ metadata { - definition (name: "Z-Wave Motion Sensor", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.motion", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, genericHandler: "Z-Wave") { + definition(name: "Z-Wave Motion Sensor", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.motion", runLocally: true, minHubCoreVersion: '000.017.0012', executeCommandsLocally: false, genericHandler: "Z-Wave") { capability "Motion Sensor" capability "Sensor" capability "Battery" capability "Health Check" capability "Tamper Alert" + capability "Configuration" - fingerprint mfr: "011F", prod: "0001", model: "0001", deviceJoinName: "Schlage Motion Sensor" // Schlage motion - fingerprint mfr: "014A", prod: "0001", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion - fingerprint mfr: "014A", prod: "0004", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion + - fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814 - fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02 - fingerprint mfr: "0060", prod: "0001", model: "0005", deviceJoinName: "Everspring Motion Detector" //Everspring SP817 - fingerprint mfr: "0060", prod: "0001", model: "0006", deviceJoinName: "Everspring Motion Detector" - fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC - fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Portable Smart Motion Sensor" - fingerprint mfr: "0214", prod: "0003", model: "0002", deviceJoinName: "BeSense Motion Detector" - fingerprint mfr: "027A", prod: "0001", model: "0005", deviceJoinName: "Zooz Outdoor Motion Sensor" - fingerprint mfr: "027A", prod: "0301", model: "0012", deviceJoinName: "Zooz Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2" + // BeSense + fingerprint mfr: "0214", prod: "0003", model: "0002", deviceJoinName: "BeSense Motion Sensor" // BeSense Motion Detector + + // Ecolink + fingerprint mfr: "014A", prod: "0001", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion //Ecolink Motion Sensor + fingerprint mfr: "014A", prod: "0004", model: "0001", deviceJoinName: "Ecolink Motion Sensor" // Ecolink motion + //Ecolink Motion Sensor + + // Enerwave + fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC //Enerwave Motion Sensor + + // Everspring + fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814 //Everspring Motion Sensor + fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02 //Everspring Motion Sensor + fingerprint mfr: "0060", prod: "0001", model: "0005", deviceJoinName: "Everspring Motion Sensor" // Everspring Motion Detector + fingerprint mfr: "0060", prod: "0001", model: "0006", deviceJoinName: "Everspring Motion Sensor" // Everspring SP817 //Everspring Motion Detector + + // GE + fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Motion Sensor" // GE Portable Smart Motion Sensor + + // Shlage + fingerprint mfr: "011F", prod: "0001", model: "0001", deviceJoinName: "Schlage Motion Sensor" // Schlage motion //Schlage Motion Sensor + + // Zooz + fingerprint mfr: "027A", prod: "0001", model: "0005", deviceJoinName: "Zooz Motion Sensor" //Zooz Outdoor Motion Sensor + fingerprint mfr: "027A", prod: "0301", model: "0012", deviceJoinName: "Zooz Motion Sensor", mnmn: "SmartThings", vid: "generic-motion-2" //Zooz Motion Sensor } simulator { @@ -44,14 +58,14 @@ metadata { } tiles(scale: 2) { - multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){ + multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) { tileAttribute("device.motion", key: "PRIMARY_CONTROL") { - attributeState("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC") - attributeState("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC") + attributeState("active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC") + attributeState("inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#CCCCCC") } } valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { - state("battery", label:'${currentValue}% battery', unit:"") + state("battery", label: '${currentValue}% battery', unit: "") } valueTile("tamper", "device.tamper", height: 2, width: 2, decoration: "flat") { state "clear", label: 'tamper clear', backgroundColor: "#ffffff" @@ -61,18 +75,46 @@ metadata { main "motion" details(["motion", "battery", "tamper"]) } + + // Preferences for Everspring SP817 + preferences { + section { + input( + title: "Settings Available For Everspring SP817 only", + description: "To apply updated device settings to the device press the tamper switch on the device three times or check the device manual.", + type: "paragraph", + element: "paragraph" + ) + input( + title: "Re-trigger Interval Setting (Everspring SP817 only):", + description: "The setting adjusts the sleep period (in seconds) after the detector has been triggered. No response will be made during this interval if a movement is presented. Longer re-trigger interval will result in longer battery life.", + name: "retriggerIntervalSettings", + type: "number", + range: "10..3600", + defaultValue: 180 + ) + } + } } def installed() { // Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "tamper", value: "clear", displayed: false) - response(initialPoll()) } def updated() { + log.debug "updated" // Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + getConfigurationCommands() +} + +def configure() { + if (isEverspringSP817()) { + state.configured = false + } + response(initialPoll()) } private getCommandClassVersions() { @@ -82,7 +124,7 @@ private getCommandClassVersions() { def parse(String description) { def result = null if (description.startsWith("Err")) { - result = createEvent(descriptionText:description) + result = createEvent(descriptionText:description) } else { def cmd = zwave.parse(description, commandClassVersions) if (cmd) { @@ -153,6 +195,7 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm def value = cmd.v1AlarmLevel == 255 ? "active" : cmd.v1AlarmLevel ?: "inactive" result << createEvent(name: "alarm $cmd.v1AlarmType", value: value, isStateChange: true, displayed: false) } + result } @@ -164,6 +207,11 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] + log.debug "isConfigured: $state.configured" + if (isEverspringSP817() && !state.configured) { + result = lateConfigure() + } + if (isEnerwave() && device.currentState('motion') == null) { // Enerwave motion doesn't always get the associationSet that the hub sends on join result << response(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId)) } @@ -236,6 +284,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { def result = null + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) log.debug "Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}" if (encapsulatedCommand) { @@ -271,9 +327,13 @@ def initialPoll() { if (isEnerwave()) { // Enerwave motion doesn't always get the associationSet that the hub sends on join request << zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:zwaveHubNodeId) } + if (isEverspringSP817()) { + request += getConfigurationCommands() + } request << zwave.batteryV1.batteryGet() request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion request << zwave.notificationV3.notificationGet(notificationType: 0x07, event: 0x08) //motion for Everspiring + log.debug "Request is: ${request}" commands(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()] } @@ -292,6 +352,49 @@ private command(physicalgraph.zwave.Command cmd) { } } +def getConfigurationCommands() { + log.debug "getConfigurationCommands" + def result = [] + + if (isEverspringSP817()) { + Integer retriggerIntervalSettings = (settings.retriggerIntervalSettings as Integer) ?: 180 // default value (parameter 4) for Everspring SP817 + + if (!state.retriggerIntervalSettings) { + state.retriggerIntervalSettings = 180 // default value (parameter 4) for Everspring SP817 + } + + if (!state.configured || (retriggerIntervalSettings != state.retriggerIntervalSettings)) { + // when state.configured is true but if there were changes made through the preferences section this flag needs to be reset + state.configured = false + result << zwave.configurationV2.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: retriggerIntervalSettings) + result << zwave.configurationV2.configurationGet(parameterNumber: 4) + } + } + + return result +} + +def lateConfigure() { + log.debug "lateConfigure" + sendHubCommand(getConfigurationCommands(), 200) +} + +def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) { + if (isEverspringSP817()) { + if (cmd.parameterNumber == 4) { + state.retriggerIntervalSettings = scaledConfigurationValue + state.configured = true + } + log.debug "Everspring Configuration Report: ${cmd}" + } + + return [:] +} + private isEnerwave() { zwaveInfo?.mfr?.equals("011A") && zwaveInfo?.prod?.equals("0601") && zwaveInfo?.model?.equals("0901") } + +private isEverspringSP817() { + zwaveInfo?.mfr?.equals("0060") && zwaveInfo?.model?.equals("0006") +} diff --git a/devicetypes/smartthings/zwave-motion-temp-light-sensor.src/zwave-motion-temp-light-sensor.groovy b/devicetypes/smartthings/zwave-motion-temp-light-sensor.src/zwave-motion-temp-light-sensor.groovy index 97a39304bc9..cbc90b47d99 100644 --- a/devicetypes/smartthings/zwave-motion-temp-light-sensor.src/zwave-motion-temp-light-sensor.groovy +++ b/devicetypes/smartthings/zwave-motion-temp-light-sensor.src/zwave-motion-temp-light-sensor.groovy @@ -26,9 +26,9 @@ metadata { capability "Temperature Measurement" capability "Configuration" - fingerprint mfr:"0371", prod:"0002", model:"0005", deviceJoinName: "Aeotec TriSensor" //ZW005-C EU - fingerprint mfr:"0371", prod:"0102", model:"0005", deviceJoinName: "Aeotec TriSensor" //ZW005-A US - fingerprint mfr:"0371", prod:"0202", model:"0005", deviceJoinName: "Aeotec TriSensor" //ZW005-B AU + fingerprint mfr:"0371", prod:"0002", model:"0005", deviceJoinName: "Aeotec Multipurpose Sensor", mnmn: "SmartThings", vid: "aeotec-trisensor" //ZW005-C EU //Aeotec TriSensor + fingerprint mfr:"0371", prod:"0102", model:"0005", deviceJoinName: "Aeotec Multipurpose Sensor", mnmn: "SmartThings", vid: "aeotec-trisensor" //ZW005-A US //Aeotec TriSensor + fingerprint mfr:"0371", prod:"0202", model:"0005", deviceJoinName: "Aeotec Multipurpose Sensor", mnmn: "SmartThings", vid: "aeotec-trisensor" //ZW005-B AU //Aeotec TriSensor } tiles(scale: 2) { @@ -193,7 +193,7 @@ def sensorMotionEvent(value) { } private secure(cmd) { - if(zwaveInfo.zw.endsWith("s")) { + if(zwaveInfo.zw.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() diff --git a/devicetypes/smartthings/zwave-mouse-trap.src/zwave-mouse-trap.groovy b/devicetypes/smartthings/zwave-mouse-trap.src/zwave-mouse-trap.groovy index 816baff09f2..a8c21967380 100644 --- a/devicetypes/smartthings/zwave-mouse-trap.src/zwave-mouse-trap.groovy +++ b/devicetypes/smartthings/zwave-mouse-trap.src/zwave-mouse-trap.groovy @@ -21,7 +21,7 @@ metadata { //capability "pestControl", enum: idle, trapArmed, trapRearmRequired, pestDetected, pestExterminated //zw:S type:0701 mfr:021F prod:0003 model:0104 ver:3.49 zwv:4.38 lib:06 cc:5E,86,72,5A,73,80,71,30,85,59,84,70 role:06 ff:8C13 ui:8C13 - fingerprint mfr: "021F", prod: "0003", model: "0104", deviceJoinName: "Dome Mouser", mnmn: "SmartThings", vid: "SmartThings-smartthings-Dome_Mouser" + fingerprint mfr: "021F", prod: "0003", model: "0104", deviceJoinName: "Dome Pest Control", mnmn: "SmartThings", vid: "SmartThings-smartthings-Dome_Mouser" //Dome Mouser } tiles(scale: 2) { @@ -198,7 +198,7 @@ def getConfigurationCommands() { cmds << zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [255]).format() // Set Firing Mode, default: 2 (Burst fire) cmds << zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, configurationValue: [2]).format() - // This parameter defines how long the Mouser will fire continuously before it starts to burst-fire, default: 360 seconds + // This parameter defines how long the Mouser will fire continuously before it starts to burst-fire, default: 360 seconds cmds << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, configurationValue: [360]).format() // Enable/Disable LED Alarm, default: 1 (enabled) cmds << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, configurationValue: [1]).format() diff --git a/devicetypes/smartthings/zwave-multi-button.src/zwave-multi-button.groovy b/devicetypes/smartthings/zwave-multi-button.src/zwave-multi-button.groovy index 908d72b8445..ba28da45259 100644 --- a/devicetypes/smartthings/zwave-multi-button.src/zwave-multi-button.groovy +++ b/devicetypes/smartthings/zwave-multi-button.src/zwave-multi-button.groovy @@ -17,19 +17,21 @@ import groovy.json.JsonOutput */ metadata { - definition (name: "Z-Wave Multi Button", namespace: "smartthings", author: "SmartThings", mcdSync: true) { + definition (name: "Z-Wave Multi Button", namespace: "smartthings", author: "SmartThings", mcdSync: true, ocfDeviceType: "x.com.st.d.remotecontroller") { capability "Button" capability "Battery" capability "Sensor" capability "Health Check" capability "Configuration" - fingerprint mfr: "010F", prod: "1001", model: "1000", deviceJoinName: "Fibaro KeyFob", mnmn: "SmartThings", vid: "generic-6-button" //EU - fingerprint mfr: "010F", prod: "1001", model: "2000", deviceJoinName: "Fibaro KeyFob", mnmn: "SmartThings", vid: "generic-6-button" //US - fingerprint mfr: "0371", prod: "0102", model: "0003", deviceJoinName: "Aeotec NanoMote Quad", mnmn: "SmartThings", vid: "generic-4-button" //US - fingerprint mfr: "0371", prod: "0002", model: "0003", deviceJoinName: "Aeotec NanoMote Quad", mnmn: "SmartThings", vid: "generic-4-button" //EU - fingerprint mfr: "0086", prod: "0101", model: "0058", deviceJoinName: "Aeotec KeyFob", mnmn: "SmartThings", vid: "generic-4-button" //US - fingerprint mfr: "0086", prod: "0001", model: "0058", deviceJoinName: "Aeotec KeyFob", mnmn: "SmartThings", vid: "generic-4-button" //EU + // While adding new device to this DTH, remember to update method getProdNumberOfButtons() + fingerprint mfr: "010F", prod: "1001", model: "1000", deviceJoinName: "Fibaro Remote Control", mnmn: "SmartThings", vid: "generic-6-button" //EU //Fibaro KeyFob + fingerprint mfr: "010F", prod: "1001", model: "2000", deviceJoinName: "Fibaro Remote Control", mnmn: "SmartThings", vid: "generic-6-button" //US //Fibaro KeyFob + fingerprint mfr: "0371", prod: "0102", model: "0003", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //US //Aeotec NanoMote Quad + fingerprint mfr: "0371", prod: "0002", model: "0003", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //EU //Aeotec NanoMote Quad + fingerprint mfr: "0086", prod: "0101", model: "0058", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //US //Aeotec KeyFob + fingerprint mfr: "0086", prod: "0001", model: "0058", deviceJoinName: "Aeotec Remote Control", mnmn: "SmartThings", vid: "generic-4-button" //EU //Aeotec KeyFob + fingerprint mfr: "010F", prod: "1001", model: "3000", deviceJoinName: "Fibaro Remote Control", mnmn: "SmartThings", vid: "generic-6-button" //AU //Fibaro KeyFob } tiles(scale: 2) { @@ -59,23 +61,12 @@ def updated() { def initialize() { - def numberOfButtons = prodNumberOfButtons[zwaveInfo.prod] - sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false) - if(isUntrackedAeotec()) { + if(isUntrackedAeotec() || isUntrackedFibaro()) { sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zwave", scheme:"untracked"]), displayed: false) } else { sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 10 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } - if(!childDevices) { - addChildButtons(numberOfButtons) - } - if(childDevices) { - def event - for(def endpoint : 1..prodNumberOfButtons[zwaveInfo.prod]) { - event = createEvent(name: "button", value: "pushed", isStateChange: true) - sendEventToChild(endpoint, event) - } - } + response([ secure(zwave.batteryV1.batteryGet()), "delay 2000", @@ -95,9 +86,23 @@ def configure() { //Makes Fibaro KeyFob buttons send all kind of supported events } } + setupChildDevices() cmds } +def setupChildDevices(){ + def numberOfButtons = prodNumberOfButtons[zwaveInfo.prod] + sendEvent(name: "numberOfButtons", value: numberOfButtons, displayed: false) + if(!childDevices) { + addChildButtons(numberOfButtons) + + for(def endpoint : 1..prodNumberOfButtons[zwaveInfo.prod]) { + def event = createEvent(name: "button", value: "pushed", isStateChange: true) + sendEventToChild(endpoint, event) + } + } +} + def parse(String description) { def result = [] if (description.startsWith("Err")) { @@ -122,12 +127,22 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat } } +def zwaveEvent(physicalgraph.zwave.commands.sceneactivationv1.SceneActivationSet cmd) { + // Below handler was tested with Aoetec KeyFob and probably will work only with it + def value = cmd.sceneId % 2 ? "pushed" : "held" + def childId = (int)(cmd.sceneId / 2) + (cmd.sceneId % 2) + def description = "Button no. ${childId} was ${value}" + def event = createEvent(name: "button", value: value, descriptionText: description, data: [buttonNumber: childId], isStateChange: true) + sendEventToChild(childId, event) + return event +} + def zwaveEvent(physicalgraph.zwave.commands.centralscenev1.CentralSceneNotification cmd) { def value = eventsMap[(int) cmd.keyAttributes] def description = "Button no. ${cmd.sceneNumber} was ${value}" - def event = createEvent(name: "button", value: value, descriptionText: description, data: [buttonNumber: cmd.sceneNumber], isStateChange: true) - sendEventToChild(cmd.sceneNumber, event) - return createEvent(descriptionText: description) + def childEvent = createEvent(name: "button", value: value, descriptionText: description, data: [buttonNumber: cmd.sceneNumber], isStateChange: true) + sendEventToChild(cmd.sceneNumber, childEvent) + return createEvent(name: "button", value: value, descriptionText: description, data: [buttonNumber: cmd.sceneNumber], isStateChange: true, displayed: false) } def sendEventToChild(buttonNumber, event) { @@ -164,7 +179,7 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { } private secure(cmd) { - if(zwaveInfo.zw.endsWith("s")) { + if(zwaveInfo.zw.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() @@ -193,20 +208,22 @@ private addChildButtons(numberOfButtons) { private getEventsMap() {[ 0: "pushed", 1: "held", - //2: "down_hold", + 2: "down_hold", 3: "double", - //4: "pushed_3x" + 4: "pushed_3x" ]} private getProdNumberOfButtons() {[ "1001" : 6, "0102" : 4, - "0002" : 4 + "0002" : 4, + "0101" : 4, + "0001" : 4 ]} private getSupportedButtonValues() { def values = ["pushed", "held"] - if (isFibaro()) values << "double" + if (isFibaro()) values += ["double", "down_hold", "pushed_3x"] return values } @@ -214,10 +231,14 @@ private isFibaro() { zwaveInfo.mfr?.contains("010F") } +private isUntrackedFibaro() { + isFibaro() && zwaveInfo.prod?.contains("1001") +} + private isUntrackedAeotec() { zwaveInfo.mfr?.contains("0371") && zwaveInfo.model?.contains("0003") } private isAeotecKeyFob() { zwaveInfo.mfr?.contains("0086") -} \ No newline at end of file +} diff --git a/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy b/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy index 00d185d0637..36a964cacf3 100644 --- a/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy +++ b/devicetypes/smartthings/zwave-multi-metering-switch.src/zwave-multi-metering-switch.groovy @@ -24,12 +24,12 @@ metadata { command "reset" - fingerprint mfr:"0086", prod:"0003", model:"0084", deviceJoinName: "Aeotec Nano Switch 1" - fingerprint mfr:"0086", prod:"0103", model:"0084", deviceJoinName: "Aeotec Nano Switch 1" - fingerprint mfr:"0086", prod:"0203", model:"0084", deviceJoinName: "Aeotec Nano Switch 1" //AU - fingerprint mfr: "0000", cc: "0x5E,0x25,0x27,0x32,0x81,0x71,0x60,0x8E,0x2C,0x2B,0x70,0x86,0x72,0x73,0x85,0x59,0x98,0x7A,0x5A", ccOut:"0x82", ui:"0x8700", deviceJoinName: "Aeotec Nano Switch 1" - fingerprint mfr: "027A", prod: "A000", model: "A004", deviceJoinName: "Zooz ZEN Power Strip" - fingerprint mfr: "027A", prod: "A000", model: "A003", deviceJoinName: "Zooz Double Plug" + fingerprint mfr:"0086", prod:"0003", model:"0084", deviceJoinName: "Aeotec Switch 1" //Aeotec Nano Switch 1 + fingerprint mfr:"0086", prod:"0103", model:"0084", deviceJoinName: "Aeotec Switch 1" //Aeotec Nano Switch 1 + fingerprint mfr:"0086", prod:"0203", model:"0084", deviceJoinName: "Aeotec Switch 1" //AU //Aeotec Nano Switch 1 + fingerprint mfr: "0000", cc: "0x5E,0x25,0x27,0x32,0x81,0x71,0x60,0x8E,0x2C,0x2B,0x70,0x86,0x72,0x73,0x85,0x59,0x98,0x7A,0x5A", ccOut:"0x82", ui:"0x8700", deviceJoinName: "Aeotec Switch 1" //Aeotec Nano Switch 1 + fingerprint mfr: "027A", prod: "A000", model: "A004", deviceJoinName: "Zooz Switch" //Zooz ZEN Power Strip + fingerprint mfr: "027A", prod: "A000", model: "A003", deviceJoinName: "Zooz Switch" //Zooz Double Plug } tiles(scale: 2){ @@ -157,6 +157,14 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd, ep = null) { log.debug "Multichannel command ${cmd}" + (ep ? " from endpoint $ep" : "") + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand() zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer) } @@ -322,7 +330,7 @@ private encap(cmd, endpoint = null) { cmd = zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd) } - if (zwaveInfo.zw.endsWith("s")) { + if (zwaveInfo.zw.contains("s")) { zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() } else { cmd.format() diff --git a/devicetypes/smartthings/zwave-plus-door-window-sensor.src/zwave-plus-door-window-sensor.groovy b/devicetypes/smartthings/zwave-plus-door-window-sensor.src/zwave-plus-door-window-sensor.groovy index bddef4254ab..db5a02273d8 100644 --- a/devicetypes/smartthings/zwave-plus-door-window-sensor.src/zwave-plus-door-window-sensor.groovy +++ b/devicetypes/smartthings/zwave-plus-door-window-sensor.src/zwave-plus-door-window-sensor.groovy @@ -29,9 +29,9 @@ metadata { attribute "WakeUp", "string" attribute "WirelessConfig", "string" - fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x98, 0x86, 0x72, 0x5A, 0x85, 0x59, 0x73, 0x80, 0x71, 0x70, 0x84, 0x7A" - fingerprint type:"8C07", inClusters: "5E,98,86,72,5A,71" - fingerprint mfr:"0109", prod:"2001", model:"0106" // not using deviceJoinName because it's sold under different brand names + fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x98, 0x86, 0x72, 0x5A, 0x85, 0x59, 0x73, 0x80, 0x71, 0x70, 0x84, 0x7A", deviceJoinName: "Open/Closed Sensor" + fingerprint type:"8C07", inClusters: "5E,98,86,72,5A,71", deviceJoinName: "Open/Closed Sensor" + fingerprint mfr:"0109", prod:"2001", model:"0106", deviceJoinName: "Open/Closed Sensor"// not using deviceJoinName because it's sold under different brand names } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy b/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy index 0d7ab4e5d8f..67617607f9c 100644 --- a/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy +++ b/devicetypes/smartthings/zwave-plus-motion-temp-sensor.src/zwave-plus-motion-temp-sensor.groovy @@ -30,9 +30,9 @@ metadata { attribute "WakeUp", "string" attribute "WirelessConfig", "string" - fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x98, 0x86, 0x72, 0x5A, 0x85, 0x59, 0x73, 0x80, 0x71, 0x31, 0x70, 0x84, 0x7A" - fingerprint type:"8C07", inClusters: "5E,98,86,72,5A,31,71" - fingerprint mfr:"0109", prod:"2002", model:"0205" // not using deviceJoinName because it's sold under different brand names + fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x98, 0x86, 0x72, 0x5A, 0x85, 0x59, 0x73, 0x80, 0x71, 0x31, 0x70, 0x84, 0x7A", deviceJoinName: "Motion Sensor" + fingerprint type:"8C07", inClusters: "5E,98,86,72,5A,31,71", deviceJoinName: "Motion Sensor" + fingerprint mfr:"0109", prod:"2002", model:"0205", deviceJoinName: "Motion Sensor"// not using deviceJoinName because it's sold under different brand names } tiles(scale: 2) { @@ -330,7 +330,7 @@ private secureSequence(commands, delay=200) { private isSecured() { if (zwaveInfo && zwaveInfo.zw) { - return zwaveInfo.zw.endsWith("s") + return zwaveInfo.zw.contains("s") } else { return state.sec == 1 } diff --git a/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy b/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy index 8f22e275b12..7e4ee20830b 100644 --- a/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy +++ b/devicetypes/smartthings/zwave-radiator-thermostat.src/zwave-radiator-thermostat.groovy @@ -23,10 +23,11 @@ metadata { capability "Temperature Measurement" capability "Configuration" - fingerprint mfr: "0060", prod: "0015", model: "0001", deviceJoinName: "Everspring Thermostatic Radiator Valve", mnmn: "SmartThings", vid: "generic-radiator-thermostat" + fingerprint mfr: "0060", prod: "0015", model: "0001", deviceJoinName: "Everspring Thermostat", mnmn: "SmartThings", vid: "generic-radiator-thermostat" //Everspring Thermostatic Radiator Valve //this DTH is sending temperature setpoint commands using Celsius scale and assumes that they'll be handled correctly by device //if new device added to this DTH won't be able to do that, make sure to you'll handle conversion in a right way - fingerprint mfr: "0002", prod: "0115", model: "A010", deviceJoinName: "POPP Radiator Thermostat Valve", mnmn: "SmartThings", vid: "generic-radiator-thermostat-2" + fingerprint mfr: "0002", prod: "0115", model: "A010", deviceJoinName: "POPP Thermostat", mnmn: "SmartThings", vid: "generic-radiator-thermostat-2" //POPP Radiator Thermostat Valve + fingerprint mfr: "0371", prod: "0002", model: "0015", deviceJoinName: "Aeotec Thermostat", mnmn: "SmartThings", vid: "aeotec-radiator-thermostat" //Aeotec Radiator Thermostat ZWA021 } tiles(scale: 2) { @@ -93,6 +94,7 @@ def initialize() { } def installed() { + state.isSetpointChangeRequestedByController = false initialize() } @@ -135,7 +137,9 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat def zwaveEvent(physicalgraph.zwave.commands.multicmdv1.MultiCmdEncap cmd) { cmd.encapsulatedCommands().collect { encapsulatedCommand -> - zwaveEvent(encapsulatedCommand) + isPoppRadiatorThermostat() ? zwaveEvent(encapsulatedCommand, true) : zwaveEvent(encapsulatedCommand) + //in case any future device would support MultiCmdEncap + //and won't need any special handler, like POPP does }.flatten() } @@ -165,6 +169,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeRepor map.value = "heat" break case 11: + case 15: map.value = "emergency heat" break case 0: @@ -174,9 +179,22 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeRepor createEvent(map) } -def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd) { +def updateSetpoint(cmd) { def deviceTemperatureScale = cmd.scale ? 'F' : 'C' - createEvent(name: "heatingSetpoint", value: convertTemperatureIfNeeded(cmd.scaledValue, deviceTemperatureScale, cmd.precision), unit: temperatureScale) + def setpoint = Float.parseFloat(convertTemperatureIfNeeded(cmd.scaledValue, deviceTemperatureScale, cmd.precision)) + state.cachedSetpoint = setpoint + createEvent(name: "heatingSetpoint", value: setpoint, unit: temperatureScale) +} + +def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd, isResponseOfWakeUp = false) { + if (!state.isSetpointChangeRequestedByController) { + updateSetpoint(cmd) + } else if (isResponseOfWakeUp) { + state.isSetpointChangeRequestedByController = false + updateSetpoint(cmd) + } else { + [:] + } } def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { @@ -197,7 +215,11 @@ def setThermostatMode(String mode) { modeValue = 1 break case "emergency heat": - modeValue = 11 + if (isAeotecRadiatorThermostat()) { + modeValue = 15 + } else { + modeValue = 11 + } break case "off": modeValue = 0 @@ -209,7 +231,7 @@ def setThermostatMode(String mode) { [ secure(zwave.thermostatModeV2.thermostatModeSet(mode: modeValue)), - "delay 2000", + "delay 5000", secure(zwave.thermostatModeV2.thermostatModeGet()) ] } @@ -227,7 +249,8 @@ def off() { } def setHeatingSetpoint(setpoint) { - if (isPoppRadiatorThermostat()) { + if (isPoppRadiatorThermostat() && device.status == "ONLINE") { + state.isSetpointChangeRequestedByController = true sendEvent(name: "heatingSetpoint", value: setpoint, unit: temperatureScale) } setpoint = temperatureScale == 'C' ? setpoint : fahrenheitToCelsius(setpoint) @@ -264,7 +287,7 @@ private secure(cmd) { } def multiEncap(cmds) { - if (zwaveInfo.cc.contains("8F")) { + if (zwaveInfo?.cc?.contains("8F")) { secure(zwave.multiCmdV1.multiCmdEncap().encapsulate(cmds.collect { cmd -> cmd.format() })) @@ -278,7 +301,7 @@ def multiEncap(cmds) { private getMaxHeatingSetpointTemperature() { if (isEverspringRadiatorThermostat()) { temperatureScale == 'C' ? 35 : 95 - } else if (isPoppRadiatorThermostat()) { + } else if (isPoppRadiatorThermostat() || isAeotecRadiatorThermostat()) { temperatureScale == 'C' ? 28 : 82 } else { temperatureScale == 'C' ? 30 : 86 @@ -290,13 +313,15 @@ private getMinHeatingSetpointTemperature() { temperatureScale == 'C' ? 15 : 59 } else if (isPoppRadiatorThermostat()) { temperatureScale == 'C' ? 4 : 39 + } else if (isAeotecRadiatorThermostat()) { + temperatureScale == 'C' ? 8 : 47 } else { temperatureScale == 'C' ? 10 : 50 } } private getThermostatSupportedModes() { - if (isEverspringRadiatorThermostat()) { + if (isEverspringRadiatorThermostat() || isAeotecRadiatorThermostat()) { ["off", "heat", "emergency heat"] } else if (isPoppRadiatorThermostat()) { //that's just for looking fine in Classic ["heat"] @@ -319,4 +344,8 @@ private isEverspringRadiatorThermostat() { private isPoppRadiatorThermostat() { zwaveInfo.mfr == "0002" && zwaveInfo.prod == "0115" +} + +private isAeotecRadiatorThermostat() { + zwaveInfo.mfr == "0371" && zwaveInfo.prod == "0002" } \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-range-extender.src/zwave-range-extender.groovy b/devicetypes/smartthings/zwave-range-extender.src/zwave-range-extender.groovy index 99a5f527186..f0592b8598e 100644 --- a/devicetypes/smartthings/zwave-range-extender.src/zwave-range-extender.groovy +++ b/devicetypes/smartthings/zwave-range-extender.src/zwave-range-extender.groovy @@ -15,13 +15,13 @@ metadata { definition (name: "Z-Wave Range Extender", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.networking") { capability "Health Check" - fingerprint mfr: "0086", prod: "0104", model: "0075", deviceJoinName: "Aeotec Range Extender 6" //US - fingerprint mfr: "0086", prod: "0204", model: "0075", deviceJoinName: "Aeotec Range Extender 6" //UK, AU - fingerprint mfr: "0086", prod: "0004", model: "0075", deviceJoinName: "Aeotec Range Extender 6" //EU - fingerprint mfr: "0246", prod: "0001", model: "0001", deviceJoinName: "Iris Z-Wave Range Extender (Smart Plug)" - fingerprint mfr: "021F", prod: "0003", model: "0108", deviceJoinName: "Dome Range Extender DMEX1" //US - fingerprint mfr: "0371", prod: "0104", model: "00BD", deviceJoinName: "Aeotec Range Extender 7" //US - fingerprint mfr: "0371", prod: "0004", model: "00BD", deviceJoinName: "Aeotec Range Extender 7" //EU + fingerprint mfr: "0086", prod: "0104", model: "0075", deviceJoinName: "Aeotec Repeater/Extender" //US //Aeotec Range Extender 6 + fingerprint mfr: "0086", prod: "0204", model: "0075", deviceJoinName: "Aeotec Repeater/Extender" //UK, AU //Aeotec Range Extender 6 + fingerprint mfr: "0086", prod: "0004", model: "0075", deviceJoinName: "Aeotec Repeater/Extender" //EU //Aeotec Range Extender 6 + fingerprint mfr: "0246", prod: "0001", model: "0001", deviceJoinName: "Iris Repeater/Extender" //Iris Z-Wave Range Extender (Smart Plug) + fingerprint mfr: "021F", prod: "0003", model: "0108", deviceJoinName: "Dome Repeater/Extender" //US //Dome Range Extender DMEX1 + fingerprint mfr: "0371", prod: "0104", model: "00BD", deviceJoinName: "Aeotec Repeater/Extender" //US //Aeotec Range Extender 7 + fingerprint mfr: "0371", prod: "0004", model: "00BD", deviceJoinName: "Aeotec Repeater/Extender" //EU //Aeotec Range Extender 7 } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zwave-relay.src/zwave-relay.groovy b/devicetypes/smartthings/zwave-relay.src/zwave-relay.groovy index 2a3f00e4faa..c739aa51928 100644 --- a/devicetypes/smartthings/zwave-relay.src/zwave-relay.groovy +++ b/devicetypes/smartthings/zwave-relay.src/zwave-relay.groovy @@ -22,8 +22,8 @@ metadata { capability "Health Check" capability "Relay Switch" - fingerprint deviceId: "0x1001", inClusters: "0x20,0x25,0x27,0x72,0x86,0x70,0x85" - fingerprint deviceId: "0x1003", inClusters: "0x25,0x2B,0x2C,0x27,0x75,0x73,0x70,0x86,0x72" + fingerprint deviceId: "0x1001", inClusters: "0x20,0x25,0x27,0x72,0x86,0x70,0x85", deviceJoinName: "Switch" + fingerprint deviceId: "0x1003", inClusters: "0x25,0x2B,0x2C,0x27,0x75,0x73,0x70,0x86,0x72", deviceJoinName: "Switch" } // simulator metadata diff --git a/devicetypes/smartthings/zwave-sensor.src/zwave-sensor.groovy b/devicetypes/smartthings/zwave-sensor.src/zwave-sensor.groovy index 0cd9382dcd9..26e25e9739a 100644 --- a/devicetypes/smartthings/zwave-sensor.src/zwave-sensor.groovy +++ b/devicetypes/smartthings/zwave-sensor.src/zwave-sensor.groovy @@ -325,6 +325,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { def result = null + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) log.debug "Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}" if (encapsulatedCommand) { diff --git a/devicetypes/smartthings/zwave-siren.src/i18n/messages.properties b/devicetypes/smartthings/zwave-siren.src/i18n/messages.properties new file mode 100644 index 00000000000..c7d3a81e2fe --- /dev/null +++ b/devicetypes/smartthings/zwave-siren.src/i18n/messages.properties @@ -0,0 +1,306 @@ +# Copyright 2020 SmartThings +# +# 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. + +# Device Preferences +'''Enter alarm length'''.en=Enter alarm length +'''Enter alarm length'''.en-gb=Enter alarm length +'''Enter alarm length'''.en-us=Enter alarm length +'''Enter alarm length'''.en-ca=Enter alarm length +'''Enter alarm length'''.sq=Fut kohëzgjatjen e alarmit +'''Enter alarm length'''.ar=إدخال مدة نغمة المنبه +'''Enter alarm length'''.be=Увядзіце працягласць сігнала +'''Enter alarm length'''.sr-ba=Unesi dužinu alarma +'''Enter alarm length'''.bg=Въвеждане на продължителност на алармата +'''Enter alarm length'''.ca=Introduir longitud d'alarma +'''Enter alarm length'''.zh-cn=输入闹钟长度 +'''Enter alarm length'''.zh-hk=輸入警報長度 +'''Enter alarm length'''.zh-tw=輸入警報時間長度 +'''Enter alarm length'''.hr=Unesite trajanje alarma +'''Enter alarm length'''.cs=Zadejte délku alarmu +'''Enter alarm length'''.da=Angiv varighed af alarm +'''Enter alarm length'''.nl=Alarmduur invoeren +'''Enter alarm length'''.et=Sisestage märguande pikkus +'''Enter alarm length'''.fi=Anna hälytyksen pituus +'''Enter alarm length'''.fr=Entrer la durée de l'alarme +'''Enter alarm length'''.fr-ca=Saisir la durée de l'alarme +'''Enter alarm length'''.de=Alarmlänge eingeben +'''Enter alarm length'''.el=Εισαγάγετε διάρκεια συναγερμού +'''Enter alarm length'''.iw=הזן אורך התראה +'''Enter alarm length'''.hi-in=अलार्म की लंबाई प्रविष्ट करें +'''Enter alarm length'''.hu=Adja meg a riasztás hosszát +'''Enter alarm length'''.is=Slá inn lengd viðvörunar +'''Enter alarm length'''.in=Masukkan durasi alarm +'''Enter alarm length'''.it=Inserisci durata allarme +'''Enter alarm length'''.ja=アラームの長さを入力 +'''Enter alarm length'''.ko=알람 길이를 입력하세요 +'''Enter alarm length'''.lv=Ievadiet signāla ilgumu +'''Enter alarm length'''.lt=Įveskite signalo trukmę +'''Enter alarm length'''.ms=Masukkan panjang penggera +'''Enter alarm length'''.no=Angi alarmlengde +'''Enter alarm length'''.pl=Wprowadź długość alarmu +'''Enter alarm length'''.pt=Introduzir duração do alarme +'''Enter alarm length'''.ro=Introducere durată alarmă +'''Enter alarm length'''.ru=Укажите продолжительность сигнала +'''Enter alarm length'''.sr=Unesite dužinu trajanja alarma +'''Enter alarm length'''.sk=Zadajte dĺžku alarmu +'''Enter alarm length'''.sl=Vnesite dolžino alarma +'''Enter alarm length'''.es=Introduce la duración de la alarma +'''Enter alarm length'''.sv=Ange larmlängden +'''Enter alarm length'''.th=ใส่ระยะเวลาปลุก +'''Enter alarm length'''.tr=Alarm uzunluğu girin +'''Enter alarm length'''.uk=Уведіть тривалість сигналу +'''Enter alarm length'''.vi=Nhập độ dài chuông báo +'''Alarm length'''.en=Alarm length +'''Alarm length'''.en-gb=Alarm length +'''Alarm length'''.en-us=Alarm length +'''Alarm length'''.en-ca=Alarm length +'''Alarm length'''.sq=Kohëzgjatja e alarmit +'''Alarm length'''.ar=مدة نغمة المنبه +'''Alarm length'''.be=Працягласць сігналу +'''Alarm length'''.sr-ba=Dužina alarma +'''Alarm length'''.bg=Продължителност на алармата +'''Alarm length'''.ca=Longitud d'alarma +'''Alarm length'''.zh-cn=闹钟长度 +'''Alarm length'''.zh-hk=警報長度 +'''Alarm length'''.zh-tw=警報時間長度 +'''Alarm length'''.hr=Trajanje alarma +'''Alarm length'''.cs=Délka alarmu +'''Alarm length'''.da=Varighed af alarm +'''Alarm length'''.nl=Alarmduur +'''Alarm length'''.et=Märguande pikkus +'''Alarm length'''.fi=Hälytyksen pituus +'''Alarm length'''.fr=Durée de l'alarme +'''Alarm length'''.fr-ca=Durée de l'alarme +'''Alarm length'''.de=Alarmlänge +'''Alarm length'''.el=Διάρκεια συναγερμού +'''Alarm length'''.iw=אורך התראה +'''Alarm length'''.hi-in=अलार्म की लंबाई +'''Alarm length'''.hu=Riasztás hossza +'''Alarm length'''.is=Lengd viðvörunar +'''Alarm length'''.in=Durasi alarm +'''Alarm length'''.it=Lunghezza allarme +'''Alarm length'''.ja=アラームの長さ +'''Alarm length'''.ko=알람 길이 +'''Alarm length'''.lv=Signāla ilgums +'''Alarm length'''.lt=Signalo ilgis +'''Alarm length'''.ms=Panjang penggera +'''Alarm length'''.no=Alarmlengde +'''Alarm length'''.pl=Długość alarmu +'''Alarm length'''.pt=Duração do alarme +'''Alarm length'''.ro=Lungime alarmă +'''Alarm length'''.ru=Продолжительность сигнала +'''Alarm length'''.sr=Dužina trajanja alarma +'''Alarm length'''.sk=Dĺžka alarmu +'''Alarm length'''.sl=Dolžina alarma +'''Alarm length'''.es=Duración de la alarma +'''Alarm length'''.sv=Larmlängd +'''Alarm length'''.th=ระยะเวลาเตือน +'''Alarm length'''.tr=Alarm uzunluğu +'''Alarm length'''.uk=Тривалість сигналу +'''Alarm length'''.vi=Độ dài chuông báo +'''This setting only applies to Yale sirens.'''.en=This setting only applies to Yale sirens. +'''This setting only applies to Yale sirens.'''.en-gb=This setting only applies to Yale sirens. +'''This setting only applies to Yale sirens.'''.en-us=This setting only applies to Yale sirens. +'''This setting only applies to Yale sirens.'''.en-ca=This setting only applies to Yale sirens. +'''This setting only applies to Yale sirens.'''.sq=Ky cilësim vlen vetëm për sirenat Yale. +'''This setting only applies to Yale sirens.'''.ar=ينطبق هذا الضبط على صفارات إنذار‬ Yale فقط. +'''This setting only applies to Yale sirens.'''.be=Гэта налада прымяняецца толькі да сірэн Yale. +'''This setting only applies to Yale sirens.'''.sr-ba=Ova postavka se primjenjuje isključivo na sirene kompanije Yale. +'''This setting only applies to Yale sirens.'''.bg=Тази настройка важи само за сирени от Yale. +'''This setting only applies to Yale sirens.'''.ca=Aquest ajustament només s'aplica a les sirenes Yale. +'''This setting only applies to Yale sirens.'''.zh-cn=此设置仅适用于 Yale 报警器。 +'''This setting only applies to Yale sirens.'''.zh-hk=此設定僅適用於 Yale 警報器。 +'''This setting only applies to Yale sirens.'''.zh-tw=此設定僅適用於 Yale 警報。 +'''This setting only applies to Yale sirens.'''.hr=Ova se postavka primjenjuje isključivo na sirene tvrtke Yale. +'''This setting only applies to Yale sirens.'''.cs=Toto nastavení platí pouze pro sirény Yale. +'''This setting only applies to Yale sirens.'''.da=Denne indstilling gælder kun for Yale-sirener. +'''This setting only applies to Yale sirens.'''.nl=Deze instelling geldt alleen voor Yale-alarmen. +'''This setting only applies to Yale sirens.'''.et=See seadistus kehtib ainult Yale’i sireenide puhul. +'''This setting only applies to Yale sirens.'''.fi=Tämä asetus koskee vain Yale-sireenejä. +'''This setting only applies to Yale sirens.'''.fr=Ce paramètre s'applique uniquement aux sirènes Yale. +'''This setting only applies to Yale sirens.'''.fr-ca=Ce paramètre s'applique uniquement aux sirènes Yale. +'''This setting only applies to Yale sirens.'''.de=Diese Einstellung wird nur auf Yale-Sirenen angewendet. +'''This setting only applies to Yale sirens.'''.el=Αυτή η ρύθμιση ισχύει μόνο για τους συναγερμούς Yale. +'''This setting only applies to Yale sirens.'''.iw=הגדרה זו חלה על אזעקות של Yale בלבד. +'''This setting only applies to Yale sirens.'''.hi-in=यह सेटिंग केवल येल सायरन्स पर लागू होती है। +'''This setting only applies to Yale sirens.'''.hu=Ez a beállítás csak a Yale szirénákra vonatkozik. +'''This setting only applies to Yale sirens.'''.is=Þessi stilling á aðeins við um Yale-sírenur. +'''This setting only applies to Yale sirens.'''.in=Pengaturan ini hanya berlaku bagi sirine Yale. +'''This setting only applies to Yale sirens.'''.it=Questa impostazione si applica solo alle sirene Yale. +'''This setting only applies to Yale sirens.'''.ja=この設定はYaleサイレンにのみ適用されます。 +'''This setting only applies to Yale sirens.'''.ko=이 설정은 Yale 사이렌에만 적용돼요. +'''This setting only applies to Yale sirens.'''.lv=Šis iestatījums attiecas tikai uz Yale sirēnām. +'''This setting only applies to Yale sirens.'''.lt=Šis nustatymas taikomas tik „Yale“ signalizacijoms. +'''This setting only applies to Yale sirens.'''.ms=Aturan ini hanya terpakai kepada siren Yale. +'''This setting only applies to Yale sirens.'''.no=Denne innstillingen gjelder bare Yale-sirener. +'''This setting only applies to Yale sirens.'''.pl=To ustawienie dotyczy tylko syren Yale. +'''This setting only applies to Yale sirens.'''.pt=Esta definição apenas se aplica às sirenes Yale. +'''This setting only applies to Yale sirens.'''.ro=Setarea se va aplica doar sirenelor Yale. +'''This setting only applies to Yale sirens.'''.ru=Этот параметр применяется только к сиренам Yale. +'''This setting only applies to Yale sirens.'''.sr=Ovo podešavanje se odnosi samo na Yale sirene. +'''This setting only applies to Yale sirens.'''.sk=Toto nastavenie sa vzťahuje iba na sirény Yale. +'''This setting only applies to Yale sirens.'''.sl=Ta nastavitev velja samo za sirene Yale. +'''This setting only applies to Yale sirens.'''.es=Este ajuste solo se aplica a las sirenas Yale. +'''This setting only applies to Yale sirens.'''.sv=Denna inställning gäller bara Yale-sirener. +'''This setting only applies to Yale sirens.'''.th=การตั้งค่านี้ใช้ได้กับไซเรนของ Yale เท่านั้น +'''This setting only applies to Yale sirens.'''.tr=Bu ayar sadece Yale sirenleri için geçerlidir. +'''This setting only applies to Yale sirens.'''.uk=Цей параметр стосується лише сирен Yale. +'''This setting only applies to Yale sirens.'''.vi=Cài đặt này chỉ áp dụng lên còi Yale. +'''Alarm LED flash'''.en=Alarm LED flash +'''Alarm LED flash'''.en-gb=Alarm LED flash +'''Alarm LED flash'''.en-us=Alarm LED flash +'''Alarm LED flash'''.en-ca=Alarm LED flash +'''Alarm LED flash'''.sq=Flash-i LED i alarmit +'''Alarm LED flash'''.ar=منبه ذو وميض LED +'''Alarm LED flash'''.be=Мігценне індыкатара сігналу +'''Alarm LED flash'''.sr-ba=LED blic alarma +'''Alarm LED flash'''.bg=Аларма LED светкавица +'''Alarm LED flash'''.ca=Flaix LED d'alarma +'''Alarm LED flash'''.zh-cn=闹钟 LED 闪烁 +'''Alarm LED flash'''.zh-hk=警報 LED 閃爍 +'''Alarm LED flash'''.zh-tw=LED 閃燈警報 +'''Alarm LED flash'''.hr=LED bljeskalica alarma +'''Alarm LED flash'''.cs=Blikání LED při alarmu +'''Alarm LED flash'''.da=Alarm-LED blinker +'''Alarm LED flash'''.nl=Alarm-LED met flits +'''Alarm LED flash'''.et=Märguande LED-i vilkumine +'''Alarm LED flash'''.fi=Hälytyksen merkkivalon välähdys +'''Alarm LED flash'''.fr=Alarme avec flash LED +'''Alarm LED flash'''.fr-ca=Alarme avec flash DEL +'''Alarm LED flash'''.de=Alarm-LED-Blitz +'''Alarm LED flash'''.el=Αναβοσβ. το LED του συναγερμού +'''Alarm LED flash'''.iw=הבהוב בנורית התראה +'''Alarm LED flash'''.hi-in=अलार्म LED फ्लैश +'''Alarm LED flash'''.hu=Riasztó LED-jének villogtatása +'''Alarm LED flash'''.is=Blikkandi LED-ljós með viðvörun +'''Alarm LED flash'''.in=Cahaya LED alarm +'''Alarm LED flash'''.it=Flash LED di allarme +'''Alarm LED flash'''.ja=アラームLEDフラッシュ +'''Alarm LED flash'''.ko=LED 불빛 알람 +'''Alarm LED flash'''.lv=Mirgojošs brīdinājuma LED +'''Alarm LED flash'''.lt=Signalo LED mirksėjimas +'''Alarm LED flash'''.ms=Kelip LED penggera +'''Alarm LED flash'''.no=LED-blink for alarm +'''Alarm LED flash'''.pl=Dioda LED alarmu +'''Alarm LED flash'''.pt=Flash de LED do alarme +'''Alarm LED flash'''.ro=Alarmă cu LED +'''Alarm LED flash'''.ru=Мигание во время сигнала +'''Alarm LED flash'''.sr=LED blic alarma +'''Alarm LED flash'''.sk=Blikanie poplachovej LED diódy +'''Alarm LED flash'''.sl=Bliskavica LED ob alarmu +'''Alarm LED flash'''.es=Flash LED de la alarma +'''Alarm LED flash'''.sv=Blinkande larmlysdiod +'''Alarm LED flash'''.th=กะพริบไฟ LED เตือน +'''Alarm LED flash'''.tr=Alarm LED'inin yanıp sönmesi +'''Alarm LED flash'''.uk=Блимання під час сигналу +'''Alarm LED flash'''.vi=Đèn flash LED chuông báo +'''Comfort LED (x10 sec)'''.en=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.en-gb=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.en-us=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.en-ca=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.en-ph=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.sq=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.ar=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.be=Comfort LED (×١٠‬ ثوانٍ) +'''Comfort LED (x10 sec)'''.sr-ba=Կոմֆորտ լուսադիոդ (x10 վ) +'''Comfort LED (x10 sec)'''.bg=আৰামদায়ক LED (x10 ছেকেণ্ড) +'''Comfort LED (x10 sec)'''.ca=আৰামদায়ক LED (x10 ছেকেণ্ড) +'''Comfort LED (x10 sec)'''.zh-cn=Komfort LED (x10 san) +'''Comfort LED (x10 sec)'''.zh-hk=Komfort LED (x10 san) +'''Comfort LED (x10 sec)'''.zh-tw=LED erosoa (×10 s) +'''Comfort LED (x10 sec)'''.hr=LED erosoa (×10 s) +'''Comfort LED (x10 sec)'''.cs=Comfort LED (x10 секунд) +'''Comfort LED (x10 sec)'''.da=Comfort LED (x10 секунд) +'''Comfort LED (x10 sec)'''.nl=স্বস্তিজনক LED (x10 সেকেন্ড) +'''Comfort LED (x10 sec)'''.et=স্বস্তিজনক LED (x10 সেকেন্ড) +'''Comfort LED (x10 sec)'''.fi=Bljes. LED lamp. (puta 10 sek.) +'''Comfort LED (x10 sec)'''.fr=Bljeskanje LED lampice (puta 10 sekundi) +'''Comfort LED (x10 sec)'''.fr-ca=Комфортен светодиод (x10 сек) +'''Comfort LED (x10 sec)'''.de=LED de comoditat (x10 s) +'''Comfort LED (x10 sec)'''.el=舒适 LED (x10 秒) +'''Comfort LED (x10 sec)'''.iw=舒適型 LED (x10 秒) +'''Comfort LED (x10 sec)'''.hi-in=舒適型 LED (x10 秒) +'''Comfort LED (x10 sec)'''.hu=舒適 LED (x10 秒) +'''Comfort LED (x10 sec)'''.is=舒適 LED (x10 秒) +'''Comfort LED (x10 sec)'''.in=Bljesk. LED lamp. (x10 sekundi) +'''Comfort LED (x10 sec)'''.it=Komfortní LED (x10 s) +'''Comfort LED (x10 sec)'''.ja=Komfortní LED (x10 s) +'''Comfort LED (x10 sec)'''.ko=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.lv=LED راحتی (هر ۱۰ ثانیه) +'''Comfort LED (x10 sec)'''.lt=LED راحتی (هر ۱۰ ثانیه) +'''Comfort LED (x10 sec)'''.ms=Comfort LED (x10 sec) +'''Comfort LED (x10 sec)'''.no=LED de confort (x10 segundos) +'''Comfort LED (x10 sec)'''.pl=კომფორტული LED (x10 წმ) +'''Comfort LED (x10 sec)'''.pt=კომფორტული LED (x10 წმ) +'''Comfort LED (x10 sec)'''.ro=LED άνεσης (x10 δευτ.) +'''Comfort LED (x10 sec)'''.ru=LED άνεσης (x10 δευτ.) +'''Comfort LED (x10 sec)'''.sr=અનૂકૂળ LED (x10 સે) +'''Comfort LED (x10 sec)'''.sk=נורת LED לנוחות (x10 שניות) +'''Comfort LED (x10 sec)'''.sl=कम्फर्ट LED (x10 सेकंड) +'''Comfort LED (x10 sec)'''.es=कम्फर्ट LED (x10 सेकंड) +'''Comfort LED (x10 sec)'''.sv=Komfort LED (x10 mp) +'''Comfort LED (x10 sec)'''.th=LED compoird (x10 soic) +'''Comfort LED (x10 sec)'''.tr=Comfort LED (da 10 sec) +'''Comfort LED (x10 sec)'''.uk=Comfort LED (da 10 sec) +'''Comfort LED (x10 sec)'''.vi=ಆರಾಮದಾಯಕ LED (x10 ಸೆಕೆ) +'''Tamper alert'''.en=Tamper alert +'''Tamper alert'''.en-gb=Tamper alert +'''Tamper alert'''.en-us=Tamper alert +'''Tamper alert'''.en-ca=Tamper alert +'''Tamper alert'''.en-ph=Tamper alert +'''Tamper alert'''.sq=Sinjalizim për prekje +'''Tamper alert'''.ar=تنبيه بالعبث +'''Tamper alert'''.be=Абвестка аб незаконным доступе +'''Tamper alert'''.sr-ba=Upozorenje o izmjeni +'''Tamper alert'''.bg=Известие за подправяне +'''Tamper alert'''.ca=Modificar avís +'''Tamper alert'''.zh-cn=异常提醒 +'''Tamper alert'''.zh-hk=異常提示 +'''Tamper alert'''.zh-tw=異常警報 +'''Tamper alert'''.hr=Promijeni upozorenje +'''Tamper alert'''.cs=Upozornění na manipulaci +'''Tamper alert'''.da=Ændringsvarsel +'''Tamper alert'''.nl=Melding geknoeid +'''Tamper alert'''.et=Manipuleerimise märguanne +'''Tamper alert'''.fi=Peukalointihälytys +'''Tamper alert'''.fr=Alerte d'altération +'''Tamper alert'''.fr-ca=Alerte d'altération +'''Tamper alert'''.de=Modifikationswarnung +'''Tamper alert'''.el=Ειδοποίηση τροποποίησης +'''Tamper alert'''.iw=התראת טיפול לא מורשה +'''Tamper alert'''.hi-in=छेड़छाड़ सतर्क +'''Tamper alert'''.hu=Manipulálási riasztás +'''Tamper alert'''.is=Viðvörun vegna fikts +'''Tamper alert'''.in=Peringatan gangguan +'''Tamper alert'''.it=Avviso di manomissione +'''Tamper alert'''.ja=改ざん通知 +'''Tamper alert'''.ko=비정상 조작 감지 경고 +'''Tamper alert'''.lv=Brīdinājums par iejaukšanos +'''Tamper alert'''.lt=Įsilaužimo įspėjimas +'''Tamper alert'''.ms=Amaran usikan +'''Tamper alert'''.no=Manipuleringsvarsel +'''Tamper alert'''.pl=Alert modyfikacji +'''Tamper alert'''.pt=Alerta de manipulação +'''Tamper alert'''.ro=Alertă interferențe +'''Tamper alert'''.ru=Оповещение о неисправности +'''Tamper alert'''.sr=Upozorenje na modifikovanje +'''Tamper alert'''.sk=Upozornenie na manipuláciu +'''Tamper alert'''.sl=Opozorilo o posegu +'''Tamper alert'''.es=Alerta de manipulación +'''Tamper alert'''.sv=Manipuleringsavisering +'''Tamper alert'''.th=การเตือนการดัดแปลง +'''Tamper alert'''.tr=Kurcalama uyarısı +'''Tamper alert'''.uk=Сповіщення про несправність +'''Tamper alert'''.vi=Cảnh báo nhiễu +# End of Device Preferences diff --git a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy index 167b413836a..1f95814ecaf 100644 --- a/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy +++ b/devicetypes/smartthings/zwave-siren.src/zwave-siren.groovy @@ -25,19 +25,25 @@ metadata { capability "Refresh" capability "Sensor" capability "Switch" + capability "Tamper Alert" capability "Health Check" - fingerprint inClusters: "0x20,0x25,0x86,0x80,0x85,0x72,0x71" - fingerprint mfr: "0258", prod: "0003", model: "0088", deviceJoinName: "NEO Coolcam Siren Alarm" - fingerprint mfr: "021F", prod: "0003", model: "0088", deviceJoinName: "Dome Siren" - fingerprint mfr: "0060", prod: "000C", model: "0001", deviceJoinName: "Utilitech Siren" + fingerprint inClusters: "0x20,0x25,0x86,0x80,0x85,0x72,0x71", deviceJoinName: "Siren" + fingerprint mfr: "0258", prod: "0003", model: "0088", deviceJoinName: "NEO Coolcam Siren" //NEO Coolcam Siren Alarm + fingerprint mfr: "021F", prod: "0003", model: "0088", deviceJoinName: "Dome Siren" //Dome Siren + fingerprint mfr: "0060", prod: "000C", model: "0001", deviceJoinName: "Utilitech Siren" //Utilitech Siren //zw:F type:1005 mfr:0131 prod:0003 model:1083 ver:2.17 zwv:6.02 lib:06 cc:5E,9F,55,73,86,85,8E,59,72,5A,25,71,87,70,80,6C role:07 ff:8F00 ui:8F00 - fingerprint mfr: "0131", prod: "0003", model: "1083", deviceJoinName: "Zipato Siren Alarm" + fingerprint mfr: "0131", prod: "0003", model: "1083", deviceJoinName: "Zipato Siren" //Zipato Siren Alarm //zw:F type:1005 mfr:0258 prod:0003 model:1088 ver:2.94 zwv:4.38 lib:06 cc:5E,86,72,5A,73,70,85,59,25,71,87,80 role:07 ff:8F00 ui:8F00 (EU) - fingerprint mfr: "0258", prod: "0003", model: "1088", deviceJoinName: "NEO Coolcam Siren Alarm" + fingerprint mfr: "0258", prod: "0003", model: "1088", deviceJoinName: "NEO Coolcam Siren" //NEO Coolcam Siren Alarm //zw:Fs type:1005 mfr:0129 prod:6F01 model:0001 ver:1.04 zwv:4.33 lib:03 cc:5E,80,5A,72,73,86,70,98 sec:59,2B,71,85,25,7A role:07 ff:8F00 ui:8F00 - fingerprint mfr: "0129", prod: "6F01", model: "0001", deviceJoinName: "Yale External Siren" - fingerprint mfr: "0060", prod: "000C", model: "0002", deviceJoinName: "Everspring Outdoor Solar Siren" + fingerprint mfr: "0129", prod: "6F01", model: "0001", deviceJoinName: "Yale Siren" //Yale External Siren + fingerprint mfr: "0060", prod: "000C", model: "0002", deviceJoinName: "Everspring Siren", vid: "generic-siren-12" //Everspring Outdoor Solar Siren + fingerprint mfr: "0154", prod: "0004", model: "0002", deviceJoinName: "POPP Siren", vid: "generic-siren-12" //POPP Solar Outdoor Siren + fingerprint mfr: "0109", prod: "2005", model: "0518", deviceJoinName: "Vision Siren" //Vision Outdoor Siren + fingerprint mfr: "0258", prod: "0003", model: "6088", deviceJoinName: "NEO Coolcam Siren"//AU //NEO Coolcam Siren Alarm + fingerprint mfr: "0258", prod: "0600", model: "1028", deviceJoinName: "NEO Coolcam Siren"//MY //NEO Coolcam Siren Alarm + fingerprint mfr: "0109", prod: "2009", model: "0908", deviceJoinName: "Vision Siren" //Vision Indoor Siren } simulator { @@ -66,21 +72,25 @@ metadata { standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") { state "configure", label: '', action: "configuration.configure", icon: "st.secondary.configure" } + valueTile("tamper", "device.tamper", height: 2, width: 2, decoration: "flat") { + state "clear", label: 'tamper clear', backgroundColor: "#ffffff" + state "detected", label: 'tampered', backgroundColor: "#ffffff" + } // Yale siren only preferences { - input name: "alarmLength", type: "number", title: "Alarm length", range: "1..10" + input name: "alarmLength", type: "number", title: "Alarm length", description: "Enter alarm length", range: "1..10" // defaultValue: 10 - input name: "alarmLEDflash", type: "bool", title: "Alarm LED flash" + input name: "alarmLEDflash", type: "bool", title: "Alarm LED flash", description: "This setting only applies to Yale sirens." // defaultValue: false - input name: "comfortLED", type: "number", title: "Comfort LED (x10 sec.)", range: "0..25" + input name: "comfortLED", type: "number", title: "Comfort LED (x10 sec)", description: "This setting only applies to Yale sirens.", range: "0..25" // defaultValue: 0 - input name: "tamper", type: "bool", title: "Tamper alert" + input name: "tamper", type: "bool", title: "Tamper alert", description: "This setting only applies to Yale sirens." // defaultValue: false } main "alarm" - details(["alarm", "off", "refresh", "battery", "configure"]) + details(["alarm", "off", "refresh", "tamper" ,"battery", "configure"]) } } @@ -101,6 +111,7 @@ def updated() { state.configured = false state.initializeAttempts = 0 // Device-Watch simply pings if no device events received for 122min(checkInterval) + sendEvent(name: "tamper", value: "clear") sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, isStateChanged: true, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"]) log.debug "updated(): Schedule in ${INIT_VERIFY_CHECK_PERIODIC_SECS} secs to verify initilization" runIn(INIT_VERIFY_CHECK_PERIODIC_SECS, "initializeCallback", [overwrite: true, forceForLocallyExecuting: true]) @@ -123,7 +134,7 @@ def initialize() { log.warn "Initializition of ${device.displayName} has failed with too many attempts" return } - + def cmds = [] if (!device.currentState("alarm")) { @@ -133,7 +144,7 @@ def initialize() { } } if (!device.currentState("battery")) { - if (zwaveInfo?.cc?.contains("80")) { + if (zwaveInfo?.cc?.contains("80") || zwaveInfo?.sec?.contains("80")) { cmds << secure(zwave.batteryV1.batteryGet()) } else { // Right now this DTH assumes all devices are battery powered, in the event a device is wall powered we should populate something @@ -176,6 +187,10 @@ def getYaleDefaults() { 4: false] } +def getEverspringDefaultAlarmLength() { + return 180 +} + def getConfigurationCommands() { log.debug "getConfigurationCommands" def cmds = [] @@ -221,6 +236,21 @@ def getConfigurationCommands() { // if there's nothing to configure, we're configured state.configured = true } + + if (isEverspring()) { + if (!state.alarmLength) { + state.alarmLength = everspringDefaultAlarmLength + } + Short alarmLength = (settings.alarmLength as Short) ?: everspringDefaultAlarmLength + + if (alarmLength != state.alarmLength) { + alarmLength = calcEverspringAlarmLen(alarmLength) + state.alarmLength = alarmLength + log.debug "alarm settings: ${alarmLength}" + } + cmds << secure(zwave.configurationV2.configurationSet(parameterNumber: 1, size: 2, configurationValue: [0,alarmLength])) + } + if (cmds.size > 0) { // send this last to confirm we were heard cmds << secure(zwave.configurationV2.configurationGet(parameterNumber: 1)) @@ -228,7 +258,6 @@ def getConfigurationCommands() { cmds } - def poll() { if (secondsPast(state.lastbatt, 36 * 60 * 60)) { return secure(zwave.batteryV1.batteryGet()) @@ -310,11 +339,11 @@ def parse(String description) { result = createEvent(descriptionText: description, displayed: false) } else { result = createEvent( - descriptionText: "This device failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.", - eventType: "ALERT", - name: "secureInclusion", - value: "failed", - displayed: true, + descriptionText: "This device failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.", + eventType: "ALERT", + name: "secureInclusion", + value: "failed", + displayed: true, ) } } else { @@ -360,6 +389,7 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport } else { state.configured = true } + log.debug "configuration report: ${cmd}" return [:] } @@ -422,6 +452,16 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm } result << createEvent([name: "switch", value: isActive ? "on" : "off", displayed: true]) result << createEvent([name: "alarm", value: isActive ? "both" : "off", displayed: true]) + } else if (cmd.notificationType == 0x07) { //Tamper Alert + switch (cmd.event) { + case 0x00: //Tamper switch is pressed more than 3 sec + result << createEvent([name: "tamper", value: "clear"]) + break + case 0x03: //Tamper switch is pressed more than 3 sec and released + result << createEvent([name: "tamper", value: "detected"]) + result << createEvent([name: "alarm", value: "both"]) + break + } } result } @@ -443,6 +483,16 @@ private Boolean secondsPast(timestamp, seconds) { return (new Date().time - timestamp) > (seconds * 1000) } +def calcEverspringAlarmLen(int alarmLength) { + //If the siren is Everspring then the alarm length can be set to 1, 2 or max 3 minutes + def map = [1:60, 2:120, 3:180] + if (alarmLength > 3) { + return everspringDefaultAlarmLength + } else { + return map[alarmLength].value + } +} + def isYale() { (zwaveInfo?.mfr == "0129" && zwaveInfo?.prod == "6F01" && zwaveInfo?.model == "0001") } @@ -454,3 +504,7 @@ def isZipato() { def isUtilitech() { (zwaveInfo?.mfr == "0060" && zwaveInfo?.prod == "000C" && zwaveInfo?.model == "0001") } + +def isEverspring() { + (zwaveInfo?.mfr == "0060" && zwaveInfo?.prod == "000C" && zwaveInfo?.model == "0002") +} diff --git a/devicetypes/smartthings/zwave-smoke-alarm.src/zwave-smoke-alarm.groovy b/devicetypes/smartthings/zwave-smoke-alarm.src/zwave-smoke-alarm.groovy index 1cd75fa26bd..e09023afd4f 100644 --- a/devicetypes/smartthings/zwave-smoke-alarm.src/zwave-smoke-alarm.groovy +++ b/devicetypes/smartthings/zwave-smoke-alarm.src/zwave-smoke-alarm.groovy @@ -19,9 +19,9 @@ metadata { capability "Battery" capability "Health Check" - attribute "alarmState", "string" - - fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)" + fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector" //First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO) + fingerprint mfr:"0138", prod:"0001", model:"0003", deviceJoinName: "First Alert Smoke Detector" //First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO) + fingerprint mfr:"0154", prod:"0004", model:"0003", deviceJoinName: "POPP Carbon Monoxide Sensor", mnmn: "SmartThings", vid: "generic-carbon-monoxide-3" //POPP Co Detector } simulator { @@ -36,19 +36,23 @@ metadata { tiles (scale: 2){ multiAttributeTile(name:"smoke", type: "lighting", width: 6, height: 4){ - tileAttribute ("device.alarmState", key: "PRIMARY_CONTROL") { + tileAttribute ("device.smoke", key: "PRIMARY_CONTROL") { attributeState("clear", label:"clear", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff") - attributeState("smoke", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13") - attributeState("carbonMonoxide", label:"MONOXIDE", icon:"st.alarm.carbon-monoxide.carbon-monoxide", backgroundColor:"#e86d13") + attributeState("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13") attributeState("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13") } } + standardTile("co", "device.carbonMonoxide", width:6, height:4, inactiveLabel: false, decoration: "flat") { + state("clear", label:"clear", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff") + state("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13") + state("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13") + } valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "battery", label:'${currentValue}% battery', unit:"" } main "smoke" - details(["smoke", "battery"]) + details(["smoke", "co", "battery"]) } } @@ -120,8 +124,7 @@ def createSmokeOrCOEvents(name, results) { name = "clear" break } - // This composite event is used for updating the tile - results << createEvent(name: "alarmState", value: name, descriptionText: text) + results } def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd, results) { @@ -188,13 +191,16 @@ def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd, def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd, results) { results << createEvent(descriptionText: "$device.displayName woke up", isStateChange: false) if (!state.lastbatt || (now() - state.lastbatt) >= 56*60*60*1000) { - results << response([ + results << response(delayBetween([ + zwave.notificationV3.notificationGet(notificationType: 0x01).format(), zwave.batteryV1.batteryGet().format(), - "delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format() - ]) + ], 2000)) } else { - results << response(zwave.wakeUpV1.wakeUpNoMoreInformation()) + results << response(delayBetween([ + zwave.notificationV3.notificationGet(notificationType: 0x01).format(), + zwave.wakeUpV1.wakeUpNoMoreInformation().format() + ], 2000)) } } diff --git a/devicetypes/smartthings/zwave-sound-sensor.src/zwave-sound-sensor.groovy b/devicetypes/smartthings/zwave-sound-sensor.src/zwave-sound-sensor.groovy index d5dcb267300..4ca5307fec2 100644 --- a/devicetypes/smartthings/zwave-sound-sensor.src/zwave-sound-sensor.groovy +++ b/devicetypes/smartthings/zwave-sound-sensor.src/zwave-sound-sensor.groovy @@ -18,7 +18,7 @@ metadata { capability "Battery" capability "Health Check" - fingerprint mfr: "014A", prod: "0005", model: "000F", deviceJoinName: "Ecolink Firefighter" + fingerprint mfr: "014A", prod: "0005", model: "000F", deviceJoinName: "Ecolink Sound Sensor" //Ecolink Firefighter } tiles (scale: 2) { diff --git a/devicetypes/smartthings/zwave-switch-battery.src/zwave-switch-battery.groovy b/devicetypes/smartthings/zwave-switch-battery.src/zwave-switch-battery.groovy index db786235925..b68b6a49562 100644 --- a/devicetypes/smartthings/zwave-switch-battery.src/zwave-switch-battery.groovy +++ b/devicetypes/smartthings/zwave-switch-battery.src/zwave-switch-battery.groovy @@ -21,15 +21,15 @@ metadata { capability "Switch" //zw:F type:1001 mfr:014A prod:0006 model:0002 ver:10.01 zwv:4.38 lib:03 cc:5E,86,72,73,80,25,85,59,7A role:07 ff:9D00 ui:9D00 - fingerprint mfr:"014A", prod:"0006", model:"0002", deviceJoinName: "Ecolink Z-Wave Plus Toggle Light Switch" + fingerprint mfr:"014A", prod:"0006", model:"0002", deviceJoinName: "Ecolink Switch" //Ecolink Z-Wave Plus Toggle Light Switch //zw:F type:1001 mfr:014A prod:0006 model:0003 ver:10.01 zwv:4.38 lib:03 cc:5E,86,72,73,80,25,85,59,7A role:07 ff:9D00 ui:9D00 - fingerprint mfr:"014A", prod:"0006", model:"0003", deviceJoinName: "Ecolink Z-Wave Plus Smart Switch - Dual Rocker" + fingerprint mfr:"014A", prod:"0006", model:"0003", deviceJoinName: "Ecolink Switch" //Ecolink Z-Wave Plus Smart Switch - Dual Rocker //zw:F type:1001 mfr:014A prod:0006 model:0004 ver:10.01 zwv:4.38 lib:03 cc:5E,86,72,73,80,25,85,59,7A role:07 ff:9D00 ui:9D00 - fingerprint mfr:"014A", prod:"0006", model:"0004", deviceJoinName: "Ecolink Z-Wave Plus Smart Switch - Dual Toggle" + fingerprint mfr:"014A", prod:"0006", model:"0004", deviceJoinName: "Ecolink Switch" //Ecolink Z-Wave Plus Smart Switch - Dual Toggle //zw:F type:1001 mfr:014A prod:0006 model:0005 ver:10.01 zwv:4.38 lib:03 cc:5E,86,72,73,80,25,85,59,7A role:07 ff:9D00 ui:9D00 - fingerprint mfr:"014A", prod:"0006", model:"0005", deviceJoinName: "Ecolink Z-Wave Plus Smart Switch - Single Rocker" + fingerprint mfr:"014A", prod:"0006", model:"0005", deviceJoinName: "Ecolink Switch" //Ecolink Z-Wave Plus Smart Switch - Single Rocker //zw:F type:1001 mfr:014A prod:0006 model:0006 ver:10.01 zwv:4.38 lib:03 cc:5E,86,72,73,80,25,85,59,7A role:07 ff:9D00 ui:9D00 - fingerprint mfr:"014A", prod:"0006", model:"0006", deviceJoinName: "Ecolink Z-Wave Plus Smart Switch - Single Toggle" + fingerprint mfr:"014A", prod:"0006", model:"0006", deviceJoinName: "Ecolink Switch" //Ecolink Z-Wave Plus Smart Switch - Single Toggle } tiles(scale: 2) { diff --git a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy index 971c3389ca4..2d529d5af8c 100644 --- a/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy +++ b/devicetypes/smartthings/zwave-switch-generic.src/zwave-switch-generic.groovy @@ -21,39 +21,47 @@ metadata { capability "Sensor" capability "Light" - fingerprint inClusters: "0x25", deviceJoinName: "Z-Wave Switch" - fingerprint mfr: "001D", prod: "1A02", model: "0334", deviceJoinName: "Leviton Appliance Module", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "001D", prod: "3401", model: "0001", deviceJoinName: "Leviton Switch" //Leviton DZ15S - fingerprint mfr: "0063", prod: "4F50", model: "3031", deviceJoinName: "GE Plug-in Outdoor Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0063", prod: "4F50", model: "3032", deviceJoinName: "GE Plug-in Outdoor Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0063", prod: "5250", model: "3130", deviceJoinName: "GE Plug-in Outdoor Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "001D", prod: "1D04", model: "0334", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "001D", prod: "1C02", model: "0334", deviceJoinName: "Leviton Switch" - fingerprint mfr: "001D", prod: "0301", model: "0334", deviceJoinName: "Leviton 15A Switch" - fingerprint mfr: "001D", prod: "0F01", model: "0334", deviceJoinName: "Leviton 5A Incandescent Switch" - fingerprint mfr: "001D", prod: "1603", model: "0334", deviceJoinName: "Leviton 15A Split Duplex Receptacle", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "011A", prod: "0101", model: "0102", deviceJoinName: "Enerwave On/Off Switch" - fingerprint mfr: "011A", prod: "0101", model: "0603", deviceJoinName: "Enerwave Duplex Receptacle", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0039", prod: "5052", model: "3038", deviceJoinName: "Honeywell Z-Wave Plug-in Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0039", prod: "5052", model: "3033", deviceJoinName: "Honeywell Z-Wave Plug-in Switch (Dual Outlet)", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0039", prod: "4F50", model: "3032", deviceJoinName: "Honeywell Z-Wave Plug-in Outdoor Smart Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0039", prod: "4952", model: "3036", deviceJoinName: "Honeywell Z-Wave In-Wall Smart Switch" - fingerprint mfr: "0039", prod: "4952", model: "3037", deviceJoinName: "Honeywell Z-Wave In-Wall Smart Toggle Switch" - fingerprint mfr: "0039", prod: "4952", model: "3133", deviceJoinName: "Honeywell Z-Wave In-Wall Tamper Resistant Duplex Receptacle", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "001A", prod: "5244", deviceJoinName: "Eaton RF Receptacle", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "001A", prod: "534C", model: "0000", deviceJoinName: "Eaton RF Master Switch", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "001A", prod: "5354", model: "0003", deviceJoinName: "Eaton RF Appliance Plug-In Module", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "001A", prod: "5352", model: "0000", deviceJoinName: "Eaton RF Accessory Switch" - fingerprint mfr: "014F", prod: "5753", model: "3535", deviceJoinName: "GoControl Smart In-Wall Switch" - fingerprint mfr: "014F", prod: "5257", model: "3033", deviceJoinName: "GoControl Wall Relay Switch" + fingerprint inClusters: "0x25", deviceJoinName: "Switch" //Z-Wave Switch + fingerprint mfr: "001D", prod: "1A02", model: "0334", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Appliance Module + fingerprint mfr: "001D", prod: "3401", model: "0001", deviceJoinName: "Leviton Switch" //Leviton DZ15S //Leviton Switch + fingerprint mfr: "0063", prod: "4F50", model: "3031", deviceJoinName: "GE Outlet", ocfDeviceType: "oic.d.smartplug" //GE Plug-in Outdoor Switch + fingerprint mfr: "0063", prod: "4F50", model: "3032", deviceJoinName: "GE Outlet", ocfDeviceType: "oic.d.smartplug" //GE Plug-in Outdoor Switch + fingerprint mfr: "0063", prod: "5250", model: "3130", deviceJoinName: "GE Outlet", ocfDeviceType: "oic.d.smartplug" //GE Plug-in Outdoor Switch + fingerprint mfr: "001D", prod: "1D04", model: "0334", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Outlet + fingerprint mfr: "001D", prod: "1C02", model: "0334", deviceJoinName: "Leviton Switch" //Leviton Switch + fingerprint mfr: "001D", prod: "0301", model: "0334", deviceJoinName: "Leviton Switch" //Leviton 15A Switch + fingerprint mfr: "001D", prod: "0F01", model: "0334", deviceJoinName: "Leviton Switch" //Leviton 5A Incandescent Switch + fingerprint mfr: "001D", prod: "1603", model: "0334", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton 15A Split Duplex Receptacle + fingerprint mfr: "011A", prod: "0101", model: "0102", deviceJoinName: "Enerwave Switch" //Enerwave On/Off Switch + fingerprint mfr: "011A", prod: "0101", model: "0603", deviceJoinName: "Enerwave Outlet", ocfDeviceType: "oic.d.smartplug" //Enerwave Duplex Receptacle + fingerprint mfr: "0039", prod: "5052", model: "3038", deviceJoinName: "Honeywell Outlet", ocfDeviceType: "oic.d.smartplug" //Honeywell Z-Wave Plug-in Switch + fingerprint mfr: "0039", prod: "5052", model: "3033", deviceJoinName: "Honeywell Outlet", ocfDeviceType: "oic.d.smartplug" //Honeywell Z-Wave Plug-in Switch (Dual Outlet) + fingerprint mfr: "0039", prod: "4F50", model: "3032", deviceJoinName: "Honeywell Outlet", ocfDeviceType: "oic.d.smartplug" //Honeywell Z-Wave Plug-in Outdoor Smart Switch + fingerprint mfr: "0039", prod: "4952", model: "3036", deviceJoinName: "Honeywell Switch" //Honeywell Z-Wave In-Wall Smart Switch + fingerprint mfr: "0039", prod: "4952", model: "3037", deviceJoinName: "Honeywell Switch" //Honeywell Z-Wave In-Wall Smart Toggle Switch + fingerprint mfr: "0039", prod: "4952", model: "3133", deviceJoinName: "Honeywell Outlet", ocfDeviceType: "oic.d.smartplug" //Honeywell Z-Wave In-Wall Tamper Resistant Duplex Receptacle + fingerprint mfr: "001A", prod: "5244", deviceJoinName: "Eaton Outlet", ocfDeviceType: "oic.d.smartplug" //Eaton RF Receptacle + fingerprint mfr: "001A", prod: "534C", model: "0000", deviceJoinName: "Eaton Outlet", ocfDeviceType: "oic.d.smartplug" //Eaton RF Master Switch + fingerprint mfr: "001A", prod: "5354", model: "0003", deviceJoinName: "Eaton Outlet", ocfDeviceType: "oic.d.smartplug" //Eaton RF Appliance Plug-In Module + fingerprint mfr: "001A", prod: "5352", model: "0000", deviceJoinName: "Eaton Switch" //Eaton RF Accessory Switch + fingerprint mfr: "014F", prod: "5753", model: "3535", deviceJoinName: "GoControl Switch" //GoControl Smart In-Wall Switch + fingerprint mfr: "014F", prod: "5257", model: "3033", deviceJoinName: "GoControl Switch" //GoControl Wall Relay Switch //zw:L type:1001 mfr:0307 prod:4447 model:3033 ver:5.16 zwv:4.34 lib:03 cc:5E,86,72,5A,85,59,73,25,27,70,2C,2B,5B,7A ccOut:5B role:05 ff:8700 ui:8700 - fingerprint mfr: "0307", prod: "4447", model: "3033", deviceJoinName: "Satco In-Wall Light Switch" + fingerprint mfr: "0307", prod: "4447", model: "3033", deviceJoinName: "Satco Switch" //Satco In-Wall Light Switch //zw:L type:1001 mfr:0307 prod:4447 model:3031 ver:5.06 zwv:4.05 lib:03 cc:5E,86,72,85,59,25,27,73,70,2C,2B,5A,7A role:05 ff:8700 ui:8700 - fingerprint mfr: "0307", prod: "4447", model: "3031", deviceJoinName: "Satco Plug-In Module", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "027A", prod: "B111", model: "1E1C", deviceJoinName: "Zooz Switch" - fingerprint mfr: "027A", prod: "B111", model: "251C", deviceJoinName: "Zooz Switch ZEN23" - fingerprint mfr: "0060", prod: "0004", model: "000C", deviceJoinName: "Everspring On/Off Plug", ocfDeviceType: "oic.d.smartplug" - fingerprint mfr: "0312", prod: "C000", model: "C001", deviceJoinName: "EVA LOGIK Smart Plug 1CH", ocfDeviceType: "oic.d.smartplug" + fingerprint mfr: "0307", prod: "4447", model: "3031", deviceJoinName: "Satco Outlet", ocfDeviceType: "oic.d.smartplug" //Satco Plug-In Module + fingerprint mfr: "027A", prod: "B111", model: "1E1C", deviceJoinName: "Zooz Switch" //Zooz Switch + fingerprint mfr: "027A", prod: "B111", model: "251C", deviceJoinName: "Zooz Switch" //Zooz Switch ZEN23 + fingerprint mfr: "0060", prod: "0004", model: "000C", deviceJoinName: "Everspring Outlet", ocfDeviceType: "oic.d.smartplug" //Everspring On/Off Plug + fingerprint mfr: "0312", prod: "C000", model: "C001", deviceJoinName: "EVA Outlet", ocfDeviceType: "oic.d.smartplug" //EVA LOGIK Smart Plug 1CH + fingerprint mfr: "0312", prod: "FF00", model: "FF07", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Minoston Outdoor Smart Plug + fingerprint mfr: "0312", prod: "FF00", model: "FF06", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Minoston Smart Plug 1CH + fingerprint mfr: "0312", prod: "FF00", model: "FF01", deviceJoinName: "Minoston Outlet", ocfDeviceType: "oic.d.smartplug" //Minoston on/off Toggle Switch + fingerprint mfr: "0312", prod: "C000", model: "C003", deviceJoinName: "Evalogik Outlet", ocfDeviceType: "oic.d.smartplug" //Evalogik Outdoor Smart Plug + fingerprint mfr: "0312", prod: "FF00", model: "FF03", deviceJoinName: "Minoston Switch" //Minoston Smart On/Off Switch + fingerprint mfr: "0312", prod: "C000", model: "CO05", deviceJoinName: "Evalogik Outlet", ocfDeviceType: "oic.d.smartplug" //Evalogik Mini Outdoor Smart Plug + fingerprint mfr: "031E", prod: "0004", model: "0001", deviceJoinName: "Inovelli Switch" //Inovelli Switch + fingerprint mfr: "001D", prod: "0037", model: "0002", deviceJoinName: "Leviton Outlet", ocfDeviceType: "oic.d.smartplug" //Leviton Tamper Resistant Outlet ZW15R } // simulator metadata diff --git a/devicetypes/smartthings/zwave-switch-secure.src/zwave-switch-secure.groovy b/devicetypes/smartthings/zwave-switch-secure.src/zwave-switch-secure.groovy index 704f36d2c0a..b7889d76695 100644 --- a/devicetypes/smartthings/zwave-switch-secure.src/zwave-switch-secure.groovy +++ b/devicetypes/smartthings/zwave-switch-secure.src/zwave-switch-secure.groovy @@ -20,11 +20,12 @@ metadata { capability "Sensor" capability "Health Check" - fingerprint inClusters: "0x25,0x98" - fingerprint deviceId: "0x10", inClusters: "0x98" - fingerprint mfr: "0086", prod: "0003", model: "008B", deviceJoinName: "Aeon Labs Nano Switch" - fingerprint mfr: "0086", prod: "0103", model: "008B", deviceJoinName: "Aeon Labs Nano Switch" - fingerprint mfr: "027A", prod: "A000", model: "A001", deviceJoinName: "Zooz ZEN26 Switch" + fingerprint inClusters: "0x25,0x98", deviceJoinName: "Switch" + fingerprint deviceId: "0x10", inClusters: "0x98", deviceJoinName: "Switch" + fingerprint mfr: "0086", prod: "0003", model: "008B", deviceJoinName: "Aeon Switch" //Aeon Labs Nano Switch + fingerprint mfr: "0086", prod: "0103", model: "008B", deviceJoinName: "Aeon Switch" //Aeon Labs Nano Switch + fingerprint mfr: "027A", prod: "A000", model: "A001", deviceJoinName: "Zooz Switch" //Zooz ZEN26 Switch + fingerprint mfr: "0152", prod: "A003", model: "A002", deviceJoinName: "iTec Switch" //iTec Home Light Switch } simulator { diff --git a/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy b/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy index 275a5f50132..3b75925da95 100644 --- a/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy +++ b/devicetypes/smartthings/zwave-switch.src/zwave-switch.groovy @@ -21,10 +21,10 @@ metadata { capability "Health Check" capability "Light" - fingerprint mfr:"0063", prod:"4952", deviceJoinName: "GE Wall Switch" - fingerprint mfr:"0063", prod:"5257", deviceJoinName: "GE Wall Switch" - fingerprint mfr:"0063", prod:"5052", deviceJoinName: "GE Plug-In Switch" - fingerprint mfr:"0113", prod:"5257", deviceJoinName: "Z-Wave Wall Switch" + fingerprint mfr:"0063", prod:"4952", deviceJoinName: "GE Switch" //GE Wall Switch + fingerprint mfr:"0063", prod:"5257", deviceJoinName: "GE Switch" //GE Wall Switch + fingerprint mfr:"0063", prod:"5052", deviceJoinName: "GE Switch" //GE Plug-In Switch + fingerprint mfr:"0113", prod:"5257", deviceJoinName: "Evolve Switch" //Z-Wave Wall Switch } // simulator metadata diff --git a/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy b/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy index 1eda7f5f504..ce19cc3cc43 100644 --- a/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy +++ b/devicetypes/smartthings/zwave-thermostat.src/zwave-thermostat.groovy @@ -31,11 +31,11 @@ metadata { command "poll" fingerprint deviceId: "0x08" - fingerprint inClusters: "0x43,0x40,0x44,0x31" - fingerprint mfr:"0039", prod:"0011", model:"0001", deviceJoinName: "Honeywell Z-Wave Thermostat" - fingerprint mfr:"008B", prod:"5452", model:"5439", deviceJoinName: "Trane Thermostat" - fingerprint mfr:"008B", prod:"5452", model:"5442", deviceJoinName: "Trane Thermostat" - fingerprint mfr:"008B", prod:"5452", model:"5443", deviceJoinName: "American Standard Thermostat" + fingerprint inClusters: "0x43,0x40,0x44,0x31", deviceJoinName: "Thermostat" + fingerprint mfr:"0039", prod:"0011", model:"0001", deviceJoinName: "Honeywell Thermostat" //Honeywell Z-Wave Thermostat + fingerprint mfr:"008B", prod:"5452", model:"5439", deviceJoinName: "Trane Thermostat" //Trane Thermostat + fingerprint mfr:"008B", prod:"5452", model:"5442", deviceJoinName: "Trane Thermostat" //Trane Thermostat + fingerprint mfr:"008B", prod:"5452", model:"5443", deviceJoinName: "American Standard Thermostat" //American Standard Thermostat } tiles { diff --git a/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy b/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy index ebfbe22ee10..3bef3d96056 100644 --- a/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy +++ b/devicetypes/smartthings/zwave-water-sensor.src/zwave-water-sensor.groovy @@ -24,12 +24,13 @@ metadata { capability "Health Check" capability "Configuration" - fingerprint deviceId: '0xA102', inClusters: '0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84,0x7A' - fingerprint mfr: "021F", prod: "0003", model: "0085", deviceJoinName: "Dome Leak Sensor" - fingerprint mfr: "0258", prod: "0003", model: "1085", deviceJoinName: "NEO Coolcam Water Sensor" //NAS-WS03ZE - fingerprint mfr: "0086", prod: "0102", model: "007A", deviceJoinName: "Aeotec Water Sensor 6" //US - fingerprint mfr: "0086", prod: "0002", model: "007A", deviceJoinName: "Aeotec Water Sensor 6" //EU - fingerprint mfr: "000C", prod: "0201", model: "000A", deviceJoinName: "HomeSeer LS100+ Water Sensor" + fingerprint deviceId: '0xA102', inClusters: '0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84,0x7A', deviceJoinName: "Water Leak Sensor" + fingerprint mfr: "021F", prod: "0003", model: "0085", deviceJoinName: "Dome Water Leak Sensor" //Dome Leak Sensor + fingerprint mfr: "0258", prod: "0003", model: "1085", deviceJoinName: "NEO Coolcam Water Leak Sensor" //NAS-WS03ZE //NEO Coolcam Water Sensor + fingerprint mfr: "0086", prod: "0102", model: "007A", deviceJoinName: "Aeotec Water Leak Sensor" //US //Aeotec Water Sensor 6 + fingerprint mfr: "0086", prod: "0002", model: "007A", deviceJoinName: "Aeotec Water Leak Sensor" //EU //Aeotec Water Sensor 6 + fingerprint mfr: "0086", prod: "0202", model: "007A", deviceJoinName: "Aeotec Water Leak Sensor" //AU //Aeotec Water Sensor 6 + fingerprint mfr: "000C", prod: "0201", model: "000A", deviceJoinName: "HomeSeer Water Leak Sensor" //HomeSeer LS100+ Water Sensor } simulator { @@ -57,12 +58,13 @@ metadata { } def initialize() { - if (zwaveInfo.mfr.equals("0086")) - // 8 hour (+ 2 minutes) ping for Aeotec - sendEvent(name: "checkInterval", value: (8 * 60 * 60) + 120, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) - else - // 12 hours for other devices - sendEvent(name: "checkInterval", value: (2 * 12 + 2) * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + if (isAeotec() || isNeoCoolcam() || isDome()) { + // 8 hour (+ 2 minutes) ping for Aeotec, NEO Coolcam, Dome + sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } else { + // 12 hours (+ 2 minutes) for other devices + sendEvent(name: "checkInterval", value: 12 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + } } def installed() { @@ -78,11 +80,19 @@ def updated() { } def configure() { - if (zwaveInfo.mfr.equals("0086") && zwaveInfo.model.equals("007A")) { + if (isAeotec()) { def commands = [] + commands << encap(zwave.associationV2.associationSet(groupingIdentifier:3, nodeId: [zwaveHubNodeId])) + commands << encap(zwave.associationV2.associationSet(groupingIdentifier:4, nodeId: [zwaveHubNodeId])) + // send basic sets to devices in groups 3 and 4 when water is detected + commands << encap(zwave.configurationV1.configurationSet(parameterNumber: 0x58, scaledConfigurationValue: 1, size: 1)) + commands << encap(zwave.configurationV1.configurationSet(parameterNumber: 0x59, scaledConfigurationValue: 1, size: 1)) // Tell sensor to send us battery information instead of USB power information commands << encap(zwave.configurationV1.configurationSet(parameterNumber: 0x5E, scaledConfigurationValue: 1, size: 1)) response(delayBetween(commands, 1000) + ["delay 20000", encap(zwave.wakeUpV1.wakeUpNoMoreInformation())]) + } else if (isNeoCoolcam() || isDome()) { + // wakeUpInterval set to 4 h for NEO Coolcam, Dome + zwave.wakeUpV1.wakeUpIntervalSet(seconds: 4 * 3600, nodeid: zwaveHubNodeId).format() } } @@ -250,6 +260,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) { def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) { def result = null + if (cmd.commandClass == 0x6C && cmd.parameter.size >= 4) { // Supervision encapsulated Message + // Supervision header is 4 bytes long, two bytes dropped here are the latter two bytes of the supervision header + cmd.parameter = cmd.parameter.drop(2) + // Updated Command Class/Command now with the remaining bytes + cmd.commandClass = cmd.parameter[0] + cmd.command = cmd.parameter[1] + cmd.parameter = cmd.parameter.drop(2) + } def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions) log.debug "Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}" if (encapsulatedCommand) { @@ -283,7 +301,7 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS private encap(physicalgraph.zwave.Command cmd) { if (zwaveInfo.zw.contains("s") || state.sec == 1) { secEncap(cmd) - } else if (zwaveInfo.cc.contains("56")){ + } else if (zwaveInfo?.cc?.contains("56")){ crcEncap(cmd) } else { cmd.format() @@ -297,3 +315,15 @@ private secEncap(physicalgraph.zwave.Command cmd) { private crcEncap(physicalgraph.zwave.Command cmd) { zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format() } + +private isDome() { + zwaveInfo.mfr == "021F" && zwaveInfo.model == "0085" +} + +private isNeoCoolcam() { + zwaveInfo.mfr == "0258" && zwaveInfo.model == "1085" +} + +private isAeotec() { + zwaveInfo.mfr == "0086" && zwaveInfo.model == "007A" +} \ No newline at end of file diff --git a/devicetypes/smartthings/zwave-water-temp-humidity-sensor.src/zwave-water-temp-humidity-sensor.groovy b/devicetypes/smartthings/zwave-water-temp-humidity-sensor.src/zwave-water-temp-humidity-sensor.groovy new file mode 100644 index 00000000000..01619a84f58 --- /dev/null +++ b/devicetypes/smartthings/zwave-water-temp-humidity-sensor.src/zwave-water-temp-humidity-sensor.groovy @@ -0,0 +1,230 @@ +/** + * Copyright 2020 SmartThings + * + * 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. + * + * Generic Z-Wave Water/Temp/Humidity Sensor + * + * Author: SmartThings + * Date: 2020-07-06 + */ + +metadata { + definition(name: "Z-Wave Water/Temp/Humidity Sensor", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-leak-5", ocfDeviceType: "x.com.st.d.sensor.moisture") { + capability "Water Sensor" + capability "Temperature Measurement" + capability "Relative Humidity Measurement" + capability "Tamper Alert" + capability "Battery" + capability "Sensor" + capability "Health Check" + capability "Configuration" + + fingerprint mfr:"0371", prod:"0002", model:"0013", deviceJoinName: "Aeotec Water Leak Sensor", mnmn: "SmartThings", vid: "aeotec-water-sensor-7-pro" //EU //Aeotec Water Sensor 7 Pro + fingerprint mfr:"0371", prod:"0102", model:"0013", deviceJoinName: "Aeotec Water Leak Sensor", mnmn: "SmartThings", vid: "aeotec-water-sensor-7-pro" //US //Aeotec Water Sensor 7 Pro + fingerprint mfr:"0371", prod:"0202", model:"0013", deviceJoinName: "Aeotec Water Leak Sensor", mnmn: "SmartThings", vid: "aeotec-water-sensor-7-pro" //AU //Aeotec Water Sensor 7 Pro + } + + tiles(scale: 2) { + multiAttributeTile(name: "water", type: "generic", width: 6, height: 4) { + tileAttribute("device.water", key: "PRIMARY_CONTROL") { + attributeState("dry", label:'${name}', icon: "st.alarm.water.dry", backgroundColor: "#ffffff") + attributeState("wet", label:'${name}', icon: "st.alarm.water.wet", backgroundColor: "#00A0DC") + } + } + valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "battery", label: '${currentValue}% battery' + } + valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) { + state "humidity", label: '${currentValue}% humidity', unit: "" + } + valueTile("temperature", "device.temperature", width: 2, height: 2) { + state("temperature", label: '${currentValue}°', + backgroundColors: [ + // Celsius + [value: 0, color: "#153591"], + [value: 7, color: "#1e9cbb"], + [value: 15, color: "#90d2a7"], + [value: 23, color: "#44b621"], + [value: 28, color: "#f1d801"], + [value: 35, color: "#d04e00"], + [value: 37, color: "#bc2323"], + // Fahrenheit + [value: 40, color: "#153591"], + [value: 44, color: "#1e9cbb"], + [value: 59, color: "#90d2a7"], + [value: 74, color: "#44b621"], + [value: 84, color: "#f1d801"], + [value: 95, color: "#d04e00"], + [value: 96, color: "#bc2323"] + ]) + } + valueTile("tamper", "device.tamper", height: 2, width: 2, decoration: "flat") { + state "clear", label: 'tamper clear', backgroundColor: "#ffffff" + state "detected", label: 'tampered', backgroundColor: "#ff0000" + } + + main "water" + details(["water", "humidity", "temperature", "battery", "tamper"]) + } +} + +def installed() { + clearTamper() + response([ + secure(zwave.batteryV1.batteryGet()), + "delay 500", + secure(zwave.notificationV3.notificationGet(notificationType: 0x05)), // water + "delay 500", + secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)), // temperature + "delay 500", + secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05)), // humidity + "delay 10000", + secure(zwave.wakeUpV2.wakeUpNoMoreInformation()) + ]) +} + +def updated() { + configure() +} + +def configure() { + sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 10 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) +} + +def parse(String description) { + def results = [] + + if (description.startsWith("Err")) { + results += createEvent(descriptionText: description, displayed: true) + } else { + def cmd = zwave.parse(description) + if (cmd) { + results += zwaveEvent(cmd) + } + } + + log.debug "parse() result ${results.inspect()}" + + return results +} + +def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) { + def encapsulatedCommand = cmd.encapsulatedCommand() + + if (encapsulatedCommand) { + zwaveEvent(encapsulatedCommand) + } else { + log.warn "Unable to extract encapsulated cmd from $cmd" + createEvent(descriptionText: cmd.toString()) + } +} + +def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { + if (cmd.notificationType == 0x05) { + if (cmd.event == 0x01 || cmd.event == 0x02) { + sensorWaterEvent(1) + } else if (cmd.event == 0x00) { + sensorWaterEvent(0) + } + } else if (cmd.notificationType == 0x07) { + if (cmd.event == 0x03) { + runIn(10, clearTamper, [overwrite: true, forceForLocallyExecuting: true]) + createEvent(name: "tamper", value: "detected", descriptionText: "$device.displayName was tampered") + } else if (cmd.event == 0x00) { + createEvent(name: "tamper", value: "clear") + } + } +} + +def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) { + return sensorWaterEvent(cmd.sensorValue) +} + +def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { + return sensorWaterEvent(cmd.value) +} + +def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { + def map = [name: "battery", unit: "%", isStateChange: true] + state.lastbatt = now() + + if (cmd.batteryLevel == 0xFF) { + map.value = 1 + map.descriptionText = "$device.displayName battery is low!" + } else { + map.value = cmd.batteryLevel + } + + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { + def map = [:] + + switch (cmd.sensorType) { + case 0x01: + map.name = "temperature" + map.unit = temperatureScale + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision) + break + case 0x05: + map.name = "humidity" + map.value = cmd.scaledSensorValue.toInteger() + map.unit = "%" + break + default: + map.descriptionText = cmd.toString() + } + + createEvent(map) +} + +def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) { + def cmds = [] + def result = createEvent(descriptionText: "$device.displayName woke up", isStateChange: false) + cmds += secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05)) + cmds += secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01)) + + if (!state.lastbatt || (now() - state.lastbatt) >= 10 * 60 * 60 * 1000) { + cmds += ["delay 1000", + secure(zwave.batteryV1.batteryGet()), + "delay 2000" + ] + } + + cmds += secure(zwave.wakeUpV2.wakeUpNoMoreInformation()) + + [result, response(cmds)] +} + +def zwaveEvent(physicalgraph.zwave.Command cmd) { + log.warn "Unhandled command: ${cmd}" +} + +def sensorWaterEvent(value) { + if (value) { + createEvent(name: "water", value: "wet", descriptionText: "$device.displayName detected water leakage") + } else { + createEvent(name: "water", value: "dry", descriptionText: "$device.displayName detected that leakage is no longer present") + } +} + +def clearTamper() { + sendEvent(name: "tamper", value: "clear") +} + +private secure(cmd) { + if (zwaveInfo.zw.contains("s")) { + zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format() + } else { + cmd.format() + } +} diff --git a/devicetypes/smartthings/zwave-water-temp-light-sensor.src/zwave-water-temp-light-sensor.groovy b/devicetypes/smartthings/zwave-water-temp-light-sensor.src/zwave-water-temp-light-sensor.groovy index b4309e3a95c..9d53ab989a9 100644 --- a/devicetypes/smartthings/zwave-water-temp-light-sensor.src/zwave-water-temp-light-sensor.groovy +++ b/devicetypes/smartthings/zwave-water-temp-light-sensor.src/zwave-water-temp-light-sensor.groovy @@ -25,7 +25,7 @@ metadata { capability "Temperature Measurement" capability "Illuminance Measurement" - fingerprint mfr: "019A", prod: "0003", model: "000A", deviceJoinName: "Sensative Strips Comfort/Drip" + fingerprint mfr: "019A", prod: "0003", model: "000A", deviceJoinName: "Sensative Water Leak Sensor" //Sensative Strips Comfort/Drip } simulator { diff --git a/devicetypes/smartthings/zwave-water-valve.src/zwave-water-valve.groovy b/devicetypes/smartthings/zwave-water-valve.src/zwave-water-valve.groovy index ce5b18ba84f..21ec8be715c 100644 --- a/devicetypes/smartthings/zwave-water-valve.src/zwave-water-valve.groovy +++ b/devicetypes/smartthings/zwave-water-valve.src/zwave-water-valve.groovy @@ -20,11 +20,11 @@ metadata { capability "Refresh" capability "Sensor" - fingerprint deviceId: "0x1006", inClusters: "0x25" - fingerprint mfr: "0173", prod: "0003", model: "0002", deviceJoinName: "Leak Intelligence Leak Gopher Water Shutoff Valve" - fingerprint mfr: "021F", prod: "0003", model: "0002", deviceJoinName: "Dome Water Main Shut-off" - fingerprint mfr: "0157", prod: "0003", model: "0002", deviceJoinName: "EcoNet Bulldog Valve Robot" - fingerprint mfr: "0152", prod: "0003", model: "0512", deviceJoinName: "POPP Secure Flow Stop" + fingerprint deviceId: "0x1006", inClusters: "0x25", deviceJoinName: "Valve" + fingerprint mfr: "0173", prod: "0003", model: "0002", deviceJoinName: "Leak Gopher Valve" //Leak Intelligence Leak Gopher Water Shutoff Valve + fingerprint mfr: "021F", prod: "0003", model: "0002", deviceJoinName: "Dome Valve" //Dome Water Main Shut-off + fingerprint mfr: "0157", prod: "0003", model: "0002", deviceJoinName: "EcoNet Valve" //EcoNet Bulldog Valve Robot + fingerprint mfr: "0152", prod: "0003", model: "0512", deviceJoinName: "POPP Valve" //POPP Secure Flow Stop } // simulator metadata diff --git a/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy b/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy index 7015b52076c..c43694d37e9 100644 --- a/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy +++ b/devicetypes/smartthings/zwave-window-shade.src/zwave-window-shade.groovy @@ -30,8 +30,8 @@ metadata { // This device handler is specifically for non-SWF position-aware window coverings // - fingerprint type: "0x1107", cc: "0x5E,0x26", deviceJoinName: "Window Shade" - fingerprint type: "0x9A00", cc: "0x5E,0x26", deviceJoinName: "Window Shade" + fingerprint type: "0x1107", cc: "0x5E,0x26", deviceJoinName: "Window Treatment" //Window Shade + fingerprint type: "0x9A00", cc: "0x5E,0x26", deviceJoinName: "Window Treatment" //Window Shade // fingerprint mfr:"026E", prod:"4353", model:"5A31", deviceJoinName: "Window Blinds" // fingerprint mfr:"026E", prod:"5253", model:"5A31", deviceJoinName: "Roller Shade" } @@ -80,7 +80,7 @@ metadata { } preferences { - input "preset", "number", title: "Preset position", defaultValue: 50, range: "1..100", required: false, displayDuringSetup: false + input "preset", "number", title: "Preset position", description: "Set the window shade preset position", defaultValue: 50, range: "1..100", required: false, displayDuringSetup: false } main(["windowShade"]) @@ -149,6 +149,7 @@ private handleLevelReport(physicalgraph.zwave.Command cmd) { shadeValue = "partially open" descriptionText = "${device.displayName} shade is ${level}% open" } + checkLevelReport(level) def levelEvent = createEvent(name: "level", value: level, unit: "%", displayed: false) def stateEvent = createEvent(name: "windowShade", value: shadeValue, descriptionText: descriptionText, isStateChange: levelEvent.isStateChange) @@ -166,15 +167,6 @@ def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv3.SwitchMultilevelS response(zwave.switchMultilevelV1.switchMultilevelGet().format()) ] } -def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { - def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) - updateDataValue("MSR", msr) - if (cmd.manufacturerName) { - updateDataValue("manufacturer", cmd.manufacturerName) - } - createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false]) -} - def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def map = [ name: "battery", unit: "%" ] if (cmd.batteryLevel == 0xFF) { @@ -194,6 +186,7 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) { } def open() { + levelChangeFollowUp(99) log.debug "open()" /*delayBetween([ zwave.basicV1.basicSet(value: 0xFF).format(), @@ -203,6 +196,7 @@ def open() { } def close() { + levelChangeFollowUp(0) log.debug "close()" /*delayBetween([ zwave.basicV1.basicSet(value: 0x00).format(), @@ -216,10 +210,8 @@ def setLevel(value, duration = null) { Integer level = value as Integer if (level < 0) level = 0 if (level > 99) level = 99 - delayBetween([ - zwave.basicV1.basicSet(value: level).format(), - zwave.switchMultilevelV1.switchMultilevelGet().format() - ]) + levelChangeFollowUp(level) + zwave.basicV1.basicSet(value: level).format() } def presetPosition() { @@ -246,4 +238,29 @@ def refresh() { zwave.switchMultilevelV1.switchMultilevelGet().format(), zwave.batteryV1.batteryGet().format() ], 1500) -} \ No newline at end of file +} + +def levelChangeFollowUp(expectedLevel) { + state.expectedValue = expectedLevel + state.levelChecks = 0 + runIn(5, "checkLevel", [overwrite: true]) +} + +def checkLevelReport(value) { + if (state.expectedValue != null) { + if ((state.expectedValue == 99 && value >= 99) || + (value >= state.expectedValue - 2 && value <= state.expectedValue + 2)) { + unschedule("checkLevel") + } + } +} + +def checkLevel() { + if (state.levelChecks != null && state.levelChecks < 5) { + state.levelChecks = state.levelChecks + 1 + runIn(5, "checkLevel", [overwrite: true]) + sendHubCommand(zwave.switchMultilevelV1.switchMultilevelGet()) + } else { + unschedule("checkLevel") + } +} diff --git a/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy b/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy index 59a797f8543..5d5ad2e97c3 100644 --- a/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy +++ b/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy @@ -42,7 +42,7 @@ metadata { command "eco" // Command does not exist in "Thermostat Mode" command "updateWeather" - fingerprint deviceId: "0x0806", inClusters: "0x5E,0x86,0x72,0x40,0x43,0x31,0x85,0x59,0x5A,0x73,0x20,0x42", mfr: "0239", prod: "0001", model: "0001", deviceJoinName: "Stelpro Ki Thermostat" + fingerprint deviceId: "0x0806", inClusters: "0x5E,0x86,0x72,0x40,0x43,0x31,0x85,0x59,0x5A,0x73,0x20,0x42", mfr: "0239", prod: "0001", model: "0001", deviceJoinName: "Stelpro Thermostat" //Stelpro Ki Thermostat } // simulator metadata @@ -50,11 +50,12 @@ metadata { preferences { section { - input("heatdetails", "enum", title: "Do you want a detailed operating state notification?", options: ["No", "Yes"], defaultValue: "No", required: true, displayDuringSetup: true) + input("heatdetails", "enum", title: "Do you want to see detailed operating state events in the activity history? There may be many.", options: ["No", "Yes"], defaultValue: "No", required: false, displayDuringSetup: true) } section { - input title: "Outdoor Temperature", description: "To get the current outdoor temperature to display on your thermostat enter your zip code or postal code below and make sure that your SmartThings location has a Geolocation configured (typically used for geofencing).", displayDuringSetup: false, type: "paragraph", element: "paragraph" - input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "[Do not use space](Blank = No Forecast)") + input(title: "Outdoor Temperature", description: "To get the current outdoor temperature to display on your thermostat enter your zip code or postal code below and make sure that your SmartThings location has a Geolocation configured (typically used for geofencing). Do not use space. If you don't want a forecast, leave it blank.", + displayDuringSetup: false, type: "paragraph", element: "paragraph") + input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "") } } @@ -290,7 +291,7 @@ def zwaveEvent(thermostatsetpointv2.ThermostatSetpointReport cmd) { def map = [:] if (cmd.scaledValue >= 327 || - cmd.setpointType != thermostatsetpointv2.ThermostatSetpointReport.SETPOINT_TYPE_HEATING_1) { + cmd.setpointType != thermostatsetpointv2.ThermostatSetpointReport.SETPOINT_TYPE_HEATING_1) { return [:] } temp = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision) @@ -366,7 +367,10 @@ def zwaveEvent(thermostatoperatingstatev1.ThermostatOperatingStateReport cmd) { map.name = "thermostatOperatingState" map.value = operatingState - if (settings.heatdetails == "No") { + // If the user does not want to see the Idle and Heating events in the event history, + // don't show them. Otherwise, don't show them more frequently than 5 minutes. + if (settings.heatdetails == "No" || + !secondsPast(device.currentState("thermostatOperatingState")?.getLastUpdated(), 60 * 5)) { map.displayed = false } } else { @@ -556,3 +560,25 @@ def fanCirculate() { def setThermostatFanMode() { log.trace "${device.displayName} does not support fan mode" } + +/** + * Checks if the time elapsed from the provided timestamp is greater than the number of senconds provided + * + * @param timestamp: The timestamp + * + * @param seconds: The number of seconds + * + * @returns true if elapsed time is greater than number of seconds provided, else false + */ +private Boolean secondsPast(timestamp, seconds) { + if (!(timestamp instanceof Number)) { + if (timestamp instanceof Date) { + timestamp = timestamp.time + } else if ((timestamp instanceof String) && timestamp.isNumber()) { + timestamp = timestamp.toLong() + } else { + return true + } + } + return (now() - timestamp) > (seconds * 1000) +} diff --git a/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy b/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy index 551ef5546e6..7be4b28616a 100644 --- a/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy +++ b/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy @@ -43,8 +43,8 @@ metadata { command "eco" // Command does not exist in "Thermostat Mode" command "updateWeather" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204", outClusters: "0402", manufacturer: "Stelpro", model: "STZB402+", deviceJoinName: "Stelpro Ki ZigBee Thermostat" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204", outClusters: "0402", manufacturer: "Stelpro", model: "ST218", deviceJoinName: "Stelpro ORLÉANS Convector" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204", outClusters: "0402", manufacturer: "Stelpro", model: "STZB402+", deviceJoinName: "Stelpro Thermostat" //Stelpro Ki ZigBee Thermostat + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204", outClusters: "0402", manufacturer: "Stelpro", model: "ST218", deviceJoinName: "Stelpro Thermostat" //Stelpro ORLÉANS Convector } // simulator metadata @@ -53,11 +53,12 @@ metadata { preferences { section { input("lock", "enum", title: "Do you want to lock your thermostat's physical keypad?", options: ["No", "Yes"], defaultValue: "No", required: false, displayDuringSetup: false) - input("heatdetails", "enum", title: "Do you want a detailed operating state notification?", options: ["No", "Yes"], defaultValue: "No", required: false, displayDuringSetup: true) + input("heatdetails", "enum", title: "Do you want to see detailed operating state events in the activity history? There may be many.", options: ["No", "Yes"], defaultValue: "No", required: false, displayDuringSetup: true) } section { - input title: "Outdoor Temperature", description: "To get the current outdoor temperature to display on your thermostat enter your zip code or postal code below and make sure that your SmartThings location has a Geolocation configured (typically used for geofencing).", displayDuringSetup: false, type: "paragraph", element: "paragraph" - input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "[Do not use space](Blank = No Forecast)") + input(title: "Outdoor Temperature", description: "To get the current outdoor temperature to display on your thermostat enter your zip code or postal code below and make sure that your SmartThings location has a Geolocation configured (typically used for geofencing). Do not use space. If you don't want a forecast, leave it blank.", + displayDuringSetup: false, type: "paragraph", element: "paragraph") + input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "") } } @@ -308,9 +309,9 @@ def parse(String description) { } // If the user does not want to see the Idle and Heating events in the event history, - // don't show them. Otherwise, don't show them more frequently than 30 seconds. + // don't show them. Otherwise, don't show them more frequently than 5 minutes. if (settings.heatdetails == "No" || - !secondsPast(device.currentState("thermostatOperatingState")?.getLastUpdated(), 30)) { + !secondsPast(device.currentState("thermostatOperatingState")?.getLastUpdated(), 60 * 5)) { map.displayed = false } map = validateOperatingStateBugfix(map) diff --git a/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy b/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy index f42794bfb78..59f1aae7773 100644 --- a/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy +++ b/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy @@ -43,9 +43,9 @@ metadata { command "parameterSetting" command "updateWeather" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204, 0405", outClusters: "0003, 000A, 0402", manufacturer: "Stelpro", model: "MaestroStat", deviceJoinName: "Stelpro Maestro Thermostat" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204, 0405", outClusters: "0003, 000A, 0402", manufacturer: "Stelpro", model: "SORB", deviceJoinName: "Stelpro ORLÉANS Fan Heater", mnmn: "SmartThings", vid: "SmartThings-smartthings-Stelpro_Orleans_Sonoma_Fan_Thermostat" - fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204, 0405", outClusters: "0003, 000A, 0402", manufacturer: "Stelpro", model: "SonomaStyle", deviceJoinName: "Stelpro Sonoma Style Fan Heater", mnmn: "SmartThings", vid: "SmartThings-smartthings-Stelpro_Orleans_Sonoma_Fan_Thermostat" + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204, 0405", outClusters: "0003, 000A, 0402", manufacturer: "Stelpro", model: "MaestroStat", deviceJoinName: "Stelpro Thermostat" //Stelpro Maestro Thermostat + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204, 0405", outClusters: "0003, 000A, 0402", manufacturer: "Stelpro", model: "SORB", deviceJoinName: "Stelpro Thermostat", mnmn: "SmartThings", vid: "SmartThings-smartthings-Stelpro_Orleans_Sonoma_Fan_Thermostat" //Stelpro ORLÉANS Fan Heater + fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0201, 0204, 0405", outClusters: "0003, 000A, 0402", manufacturer: "Stelpro", model: "SonomaStyle", deviceJoinName: "Stelpro Thermostat", mnmn: "SmartThings", vid: "SmartThings-smartthings-Stelpro_Orleans_Sonoma_Fan_Thermostat" //Stelpro Sonoma Style Fan Heater } // simulator metadata @@ -54,11 +54,12 @@ metadata { preferences { section { input("lock", "enum", title: "Do you want to lock your thermostat's physical keypad?", options: ["No", "Yes"], defaultValue: "No", required: false, displayDuringSetup: false) - input("heatdetails", "enum", title: "Do you want a detailed operating state notification?", options: ["No", "Yes"], defaultValue: "No", required: false, displayDuringSetup: true) + input("heatdetails", "enum", title: "Do you want to see detailed operating state events in the activity history? There may be many.", options: ["No", "Yes"], defaultValue: "No", required: false, displayDuringSetup: true) } section { - input title: "Outdoor Temperature", description: "To get the current outdoor temperature to display on your thermostat enter your zip code or postal code below and make sure that your SmartThings location has a Geolocation configured (typically used for geofencing).", displayDuringSetup: false, type: "paragraph", element: "paragraph" - input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "[Do not use space](Blank = No Forecast)") + input(title: "Outdoor Temperature", description: "To get the current outdoor temperature to display on your thermostat enter your zip code or postal code below and make sure that your SmartThings location has a Geolocation configured (typically used for geofencing). Do not use space. If you don't want a forecast, leave it blank.", + displayDuringSetup: false, type: "paragraph", element: "paragraph") + input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "") } /* input("away_setpoint", "enum", title: "Away setpoint", options: ["5", "5.5", "6", "6.5", "7", "7.5", "8", "8.5", "9", "9.5", "10", "10.5", "11", "11.5", "12", "12.5", "13", "13.5", "14", "14.5", "15", "5.5", "15.5", "16", "16.5", "17", "17.5", "18", "18.5", "19", "19.5", "20", "20.5", "21", "21.5", "22", "22.5", "23", "24", "24.5", "25", "25.5", "26", "26.5", "27", "27.5", "28", "28.5", "29", "29.5", "30"], defaultValue: "21", required: true) @@ -279,9 +280,9 @@ def parse(String description) { } // If the user does not want to see the Idle and Heating events in the event history, - // don't show them. Otherwise, don't show them more frequently than 30 seconds. + // don't show them. Otherwise, don't show them more frequently than 5 minutes. if (settings.heatdetails == "No" || - !secondsPast(device.currentState("thermostatOperatingState")?.getLastUpdated(), 30)) { + !secondsPast(device.currentState("thermostatOperatingState")?.getLastUpdated(), 60 * 5)) { map.displayed = false } } diff --git a/devicetypes/zenwithin/zen-thermostat.src/zen-thermostat.groovy b/devicetypes/zenwithin/zen-thermostat.src/zen-thermostat.groovy index 6d41ef2098b..b79ec7ed0a3 100644 --- a/devicetypes/zenwithin/zen-thermostat.src/zen-thermostat.groovy +++ b/devicetypes/zenwithin/zen-thermostat.src/zen-thermostat.groovy @@ -28,7 +28,7 @@ metadata { // To please some of the thermostat SmartApps command "poll" - fingerprint profileId: "0104", endpointId: "01", inClusters: "0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, 0019", manufacturer: "Zen Within", model: "Zen-01", deviceJoinName: "Zen Thermostat" + fingerprint profileId: "0104", endpointId: "01", inClusters: "0000,0001,0003,0004,0005,0020,0201,0202,0204,0B05", outClusters: "000A, 0019", manufacturer: "Zen Within", model: "Zen-01", deviceJoinName: "Zen Thermostat" //Zen Thermostat } tiles { diff --git a/smartapps/curb/curb-energy-monitor.src/curb-energy-monitor.groovy b/smartapps/curb/curb-energy-monitor.src/curb-energy-monitor.groovy index 57e34b9c225..9c0bf07fb53 100644 --- a/smartapps/curb/curb-energy-monitor.src/curb-energy-monitor.groovy +++ b/smartapps/curb/curb-energy-monitor.src/curb-energy-monitor.groovy @@ -26,7 +26,9 @@ definition( iconUrl: "http://energycurb.com/wp-content/uploads/2015/12/curb-web-logo.png", iconX2Url: "http://energycurb.com/wp-content/uploads/2015/12/curb-web-logo.png", iconX3Url: "http://energycurb.com/wp-content/uploads/2015/12/curb-web-logo.png", - singleInstance: true + singleInstance: true, + usesThirdPartyAuthentication: true, + pausable: false ) { appSetting "clientId" appSetting "clientSecret" diff --git a/smartapps/smartthings/button-controller.src/button-controller.groovy b/smartapps/smartthings/button-controller.src/button-controller.groovy index 07dcde42a62..542f63789c1 100644 --- a/smartapps/smartthings/button-controller.src/button-controller.groovy +++ b/smartapps/smartthings/button-controller.src/button-controller.groovy @@ -57,6 +57,10 @@ def selectButton() { input "modes", "mode", title: "Only when mode is", multiple: true, required: false } + + section([title: " ", mobileOnly:true]) { + label title: "Assign a name", required: false + } } } diff --git a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy b/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy index 284a1fda5dc..2a3a78cb1d9 100644 --- a/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy +++ b/smartapps/smartthings/ecobee-connect.src/ecobee-connect.groovy @@ -599,7 +599,7 @@ def poll() { // No need to keep trying to poll if authToken is null if (!state.authToken) { log.info "poll failed due to authToken=null" - def notificationMessage = "is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials." + def notificationMessage = "is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials." sendPushAndFeeds(notificationMessage) markChildrenOffline(true) unschedule() @@ -958,7 +958,7 @@ def toQueryString(Map m) { boolean refreshAuthToken() { log.debug "refreshing auth token" - def notificationMessage = "is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials." + def notificationMessage = "is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials." def isSuccess = false if(!state.refreshToken) { diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties index 9d52078730c..555db6a9e05 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/ar-AE.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=يتعذر إنشاء الاتصال! '''Click 'Done' to return to the menu.'''=انقر فوق ”تم“ للعودة إلى القائمة. '''is connected to SmartThings'''={{deviceName}} متصل بـ SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=تم قطع اتصال {{deviceName}} بـ SmartThings، لأن بيانات اعتماد الوصول قد تغيرت أو فُقدت. يُرجى الانتقال إلى التطبيق الذكي Ecobee (Connect)‎ وإعادة إدخال بيانات اعتماد تسجيل الدخول إلى حسابك. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=تم قطع اتصال {{deviceName}} بـ SmartThings، لأن بيانات اعتماد الوصول قد تغيرت أو فُقدت. يُرجى الانتقال إلى التطبيق الذكي Ecobee (Connect)‎ وإعادة إدخال بيانات اعتماد تسجيل الدخول إلى حسابك. '''Your Ecobee thermostat '''=ثرموستات Ecobee '''Select your ecobee devices'''=تحديد أجهزة ecobee لديك '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=انقر أدناه لإضافة أجهزة الثرموستات المتوفرة في حساب ecobee لديك أو إزالتها. سيتم توصيل أجهزة الثرموستات المحددة بـ SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties b/smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties index f90497fbe5c..19f0cf6bdd4 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/bg-BG.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Връзката не може да се осъществи! '''Click 'Done' to return to the menu.'''=Щракнете върху Done (Готово), за да се върнете към менюто. '''is connected to SmartThings'''=е свързан към SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=е прекъснат от SmartThings, тъй като идентификационните данни за достъп са променени или изгубени. Отидете в Ecobee (Connect) SmartApp и въведете отново идентификационните си данни за влизане в акаунта. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=е прекъснат от SmartThings, тъй като идентификационните данни за достъп са променени или изгубени. Отидете в Ecobee (Connect) SmartApp и въведете отново идентификационните си данни за влизане в акаунта. '''Your Ecobee thermostat '''=Вашият термостат Ecobee '''Select your ecobee devices'''=Избор на ecobee устройства '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Докоснете по-долу, за да добавите или премахнете термостатите, налични във вашия ecobee акаунт. Избраните термостати ще се свържат със SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties index 7b18c7b0285..e6364de3c01 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/ca-ES.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=¡No se ha podido establecer la conexión! '''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú. '''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. '''Your Ecobee thermostat '''=Su termostato Ecobee '''Select your ecobee devices'''=Selecciona os teus dispositivos de ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toca a continuación para engadir ou eliminar termóstatos dispoñibles na túa conta de ecobee. Os termóstatos seleccionados conectaranse a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties b/smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties index 139e6b24ccc..da3e40a8f84 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/cs-CZ.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Připojení nelze navázat! '''Click 'Done' to return to the menu.'''=Klepnutím na tlačítko „Done“ (Hotovo) se vrátíte do menu. '''is connected to SmartThings'''=je připojen ke SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=byl odpojen od systému SmartThings, protože přístupové přihlašovací údaje byly změněny nebo ztraceny. Přejděte do Ecobee (Connect) SmartApp a znovu zadejte své přihlašovací údaje k účtu. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=byl odpojen od systému SmartThings, protože přístupové přihlašovací údaje byly změněny nebo ztraceny. Přejděte do Ecobee (Connect) SmartApp a znovu zadejte své přihlašovací údaje k účtu. '''Your Ecobee thermostat '''=Termostat Ecobee '''Select your ecobee devices'''=Vyberte zařízení ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Klepnutím na následující tlačítko přidáte nebo odeberete termostaty dostupné na účtu ecobee. Vybrané termostaty budou připojeny k aplikaci SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties b/smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties index 40929b5a3c1..ab837fde6b3 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/da-DK.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Der kunne ikke oprettes forbindelse! '''Click 'Done' to return to the menu.'''=Klik på “Done” (Udført) for at vende tilbage til menuen. '''is connected to SmartThings'''=er forbundet med SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=er koblet fra SmartThings, fordi adgangslegitimationsoplysningerne er ændret eller gået tabt. Gå til Ecobee (Connect (Forbind)) SmartApp, og indtast dine kontologinoplysninger igen. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=er koblet fra SmartThings, fordi adgangslegitimationsoplysningerne er ændret eller gået tabt. Gå til Ecobee (Connect (Forbind)) SmartApp, og indtast dine kontologinoplysninger igen. '''Your Ecobee thermostat '''=Din Ecobee-termostat '''Select your ecobee devices'''=Vælg dine ecobee-enheder '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tryk herunder for at tilføje eller fjerne termostater, der er tilgængelige på din ecobee-konto. De valgte termostater bliver forbundet til SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties index f788e199d87..a5909eef5b5 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/de-DE.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Es konnte keine Verbindung hergestellt werden! '''Click 'Done' to return to the menu.'''=Klicken Sie auf „Done“ (OK), um zum Menü zurückzukehren. '''is connected to SmartThings'''=ist mit SmartThings verbunden -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=ist von SmartThings getrennt, da die Zugangsdaten für den Zugriff geändert wurden oder verloren gingen. Wechseln Sie zur ecobee (Connect)-SmartApp und geben Sie Ihre Kontozugangsdaten erneut ein. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=ist von SmartThings getrennt, da die Zugangsdaten für den Zugriff geändert wurden oder verloren gingen. Wechseln Sie zur ecobee (Connect)-SmartApp und geben Sie Ihre Kontozugangsdaten erneut ein. '''Your Ecobee thermostat '''=Ihr ecobee-Thermostat '''Select your ecobee devices'''=Wählen Sie Ihre ecobee-Geräte aus '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tippen Sie unten, um Thermostate hinzuzufügen oder zu entfernen, die in Ihrem ecobee-Konto verfügbar sind. Ausgewählte Thermostate werden mit SmartThings verbunden. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties index e5599a76b08..abe17d298d5 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/el-GR.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Δεν ήταν δυνατή η δημιουργία σύνδεσης! '''Click 'Done' to return to the menu.'''=Κάντε κλικ στο "Done" (Τέλος) για να επιστρέψετε στο μενού. '''is connected to SmartThings'''=συνδέθηκε στο SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=αποσυνδέθηκε από το SmartThings, επειδή τα διαπιστευτήρια πρόσβασης άλλαξαν ή έχουν χαθεί. Μεταβείτε στην εφαρμογή Ecobee (Connect) SmartApp και καταχωρήστε ξανά τα διαπιστευτήρια σύνδεσης για το λογαριασμό σας. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=αποσυνδέθηκε από το SmartThings, επειδή τα διαπιστευτήρια πρόσβασης άλλαξαν ή έχουν χαθεί. Μεταβείτε στην εφαρμογή Ecobee (Connect) SmartApp και καταχωρήστε ξανά τα διαπιστευτήρια σύνδεσης για το λογαριασμό σας. '''Your Ecobee thermostat '''=Θερμοστάτης Ecobee '''Select your ecobee devices'''=Επιλέξτε τις συσκευές σας ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Πατήστε παρακάτω για να προσθέσετε ή να καταργήσετε τους θερμοστάτες που είναι διαθέσιμοι στο λογαριασμό σας ecobee. Οι επιλεγμένοι θερμοστάτες θα συνδεθούν στο SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties b/smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties index 578e3831110..2e434f86057 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/en-GB.properties @@ -16,5 +16,5 @@ '''The connection could not be established!'''=The connection could not be established! '''Click 'Done' to return to the menu.'''=Click ’Done’ to return to the menu. '''is connected to SmartThings'''=is connected to SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials. '''Your Ecobee thermostat '''=Your Ecobee thermostat diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties b/smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties index 30b402c6698..387a54218c0 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/es-ES.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=¡No se ha podido establecer la conexión! '''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú. '''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. '''Your Ecobee thermostat '''=Su termostato Ecobee '''Select your ecobee devices'''=Selecciona tus dispositivos ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Pulsa a continuación para añadir o eliminar los termostatos disponibles en tu cuenta de ecobee. Los termostatos seleccionados se conectarán a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties b/smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties index 4778727afab..14b3027e7f1 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/es-MX.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=¡No se ha podido establecer la conexión! '''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú. '''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=está desconectado de SmartThings porque se han cambiado o perdido las credenciales de acceso. Vaya a la aplicación inteligente de Ecobee (Conectar) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. '''Your Ecobee thermostat '''=Su termostato Ecobee '''Select your ecobee devices'''=Seleccione sus dispositivos ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Pulse a continuación para añadir o eliminar los termostatos disponibles en su cuenta de ecobee. Los dispositivos seleccionados se conectarán a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties b/smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties index 761224ed09f..bf026c87491 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/es-US.properties @@ -16,5 +16,5 @@ '''The connection could not be established!'''=¡No fue posible establecer la conexión! '''Click 'Done' to return to the menu.'''=Haga clic en 'Done' ('Listo') para volver al menú. '''is connected to SmartThings'''=está conectado a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=no está conectado a SmartThings debido a que la credencial de acceso se cambió o se perdió. Vaya a la SmartApp de Ecobee (Connect) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=no está conectado a SmartThings debido a que la credencial de acceso se cambió o se perdió. Vaya a la SmartApp de Ecobee (Connect) y vuelva a introducir las credenciales de inicio de sesión de su cuenta. '''Your Ecobee thermostat '''=Su termostato Ecobee diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties index c09c662bc23..6a70d1e52ac 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/et-EE.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Ühenduse loomine nurjus! '''Click 'Done' to return to the menu.'''=Klõpsake valikut Valmis, et naasta menüüsse. '''is connected to SmartThings'''=on ühendatud teenusega SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=on teenusest SmartThings lahti ühendatud, kuna juurdepääsu volitus muutus või kadus. Avage rakendus Ecobee (Connect) SmartApp ja sisestage uuesti oma konto sisselogimisandmed. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=on teenusest SmartThings lahti ühendatud, kuna juurdepääsu volitus muutus või kadus. Avage rakendus Ecobee (Connect) SmartApp ja sisestage uuesti oma konto sisselogimisandmed. '''Your Ecobee thermostat '''=Teie Ecobee termostaat '''Select your ecobee devices'''=Valige oma ecobee seadmed '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toksake allpool, et lisada või eemaldada ecobee konto all olevaid termostaate. Valitud termostaadid ühendatakse teenusega SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties b/smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties index ccf273cd528..cd9eb4b092c 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/fi-FI.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Yhteyden muodostaminen epäonnistui! '''Click 'Done' to return to the menu.'''=Palaa valikkoon napsauttamalla Done (Valmis). '''is connected to SmartThings'''=on yhdistetty SmartThingsiin -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=ei enää ole yhteydessä SmartThingsiin, sillä käyttötunnukset ovat muuttuneet tai kadonneet. Siirry Ecobee (Connect) SmartAppiin ja anna tilisi kirjautumistiedot uudelleen. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=ei enää ole yhteydessä SmartThingsiin, sillä käyttötunnukset ovat muuttuneet tai kadonneet. Siirry Ecobee (Connect) SmartAppiin ja anna tilisi kirjautumistiedot uudelleen. '''Your Ecobee thermostat '''=Ecobee-termostaattisi '''Select your ecobee devices'''=Valitse ecobee-laitteet '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Napauttamalla alla voit lisätä tai poistaa ecobee-tililläsi käytettävissä olevat termostaatit. Valitut termostaatit muodostavat yhteyden SmartThingsiin. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties b/smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties index a1dd9f11883..c11220a9114 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/fr-CA.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=La connexion n'a pas pu être établie ! '''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu. '''is connected to SmartThings'''=est connecté à SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte. '''Your Ecobee thermostat '''=Votre thermostat Ecobee '''Select your ecobee devices'''=Sélectionnez vos appareils ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Touchez ci-dessous pour ajouter ou retirer des thermostats disponibles dans votre compte ecobee. Les thermostats sélectionnés se connecteront à SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties index 1f29952af11..2b065d62c9e 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/fr-FR.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=La connexion n'a pas pu être établie ! '''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu. '''is connected to SmartThings'''=est connecté à SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=est déconnecté de SmartThings, car les identifiants d'accès ont été modifiés ou perdus. Accédez à la SmartApp Ecobee (Connect) et saisissez à nouveau les informations de connexion à votre compte. '''Your Ecobee thermostat '''=Votre thermostat Ecobee '''Select your ecobee devices'''=Sélectionnez vos appareils ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Appuyez ci-dessous pour ajouter ou supprimer les thermostats disponibles dans votre compte ecobee. Les thermostats sélectionnés se connecteront à SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties index 565e9864057..a65bd0e6ea8 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/hr-HR.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Veza se nije uspostavila! '''Click 'Done' to return to the menu.'''=Kliknite „Done” (Gotovo) za vraćanje na izbornik. '''is connected to SmartThings'''=povezan je s uslugom SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=nije povezan s uslugom SmartThings jer su se pristupni podaci promijenili ili izgubili. Idite na Ecobee (Connect) SmartApp i ponovno unesite podatke za prijavu na račun. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=nije povezan s uslugom SmartThings jer su se pristupni podaci promijenili ili izgubili. Idite na Ecobee (Connect) SmartApp i ponovno unesite podatke za prijavu na račun. '''Your Ecobee thermostat '''=Termostat Ecobee '''Select your ecobee devices'''=Odaberite uređaje ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Dodirnite u nastavku da biste dodali ili uklonili termostate dostupne na računu za ecobee. Odabrani termostati povezat će se s uslugom SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties b/smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties index f301b38bd5a..4527593558c 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/hu-HU.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Nem sikerült kapcsolatot létesíteni! '''Click 'Done' to return to the menu.'''=A menühöz való visszatéréshez kattintson a „Done” (Kész) gombra. '''is connected to SmartThings'''=kapcsolódott a SmartThings rendszerhez -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=le lett választva a SmartThings rendszerről, mert megváltoztak vagy elvesztek a hozzáférési hitelesítő adatok. Adja meg újra a fiókja bejelentkezési hitelesítő adatait a Ecobee (Connect) SmartApp segítségével. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=le lett választva a SmartThings rendszerről, mert megváltoztak vagy elvesztek a hozzáférési hitelesítő adatok. Adja meg újra a fiókja bejelentkezési hitelesítő adatait a Ecobee (Connect) SmartApp segítségével. '''Your Ecobee thermostat '''=Az Ön Ecobee termosztátja '''Select your ecobee devices'''=Az ecobee eszközök kiválasztása '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Az alábbi lehetőség megérintésével veheti fel, illetve távolíthatja el az ecobee-fiókjában rendelkezésre álló termosztátokat. A kiválasztott eszközök csatlakozni fognak a SmartThings szolgáltatáshoz. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties b/smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties index 9fc8b269626..1b7f518acd8 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/it-IT.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Non è stato possibile stabilire la connessione. '''Click 'Done' to return to the menu.'''=Fate clic su “Done” (Fatto) per tornare al menu. '''is connected to SmartThings'''=connesso a SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=disconnesso da SmartThings. Le credenziali di accesso sono state modificate o sono andate perse. Andate alla SmartApp di Ecobee (Connect) e inserite nuovamente le credenziali di accesso all'account. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=disconnesso da SmartThings. Le credenziali di accesso sono state modificate o sono andate perse. Andate alla SmartApp di Ecobee (Connect) e inserite nuovamente le credenziali di accesso all'account. '''Your Ecobee thermostat '''=Il termostato Ecobee '''Select your ecobee devices'''=Selezionate i dispositivi ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toccate di seguito per aggiungere o rimuovere i termostati disponibili nell’account ecobee. I termostati selezionati si connetteranno a SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties index 19bc45b5788..0dd465aff0f 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/ko-KR.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=연결을 실행할 수 없습니다! '''Click 'Done' to return to the menu.'''=메뉴로 돌아가려면 [완료]를 클릭하세요. '''is connected to SmartThings'''=이(가) SmartThings에 연결되었습니다 -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=이(가) SmartThings에서 연결 해제되었습니다. 로그인 정보가 변경되었거나 유실되었습니다. Ecobee (연결) 스마트앱에서 계정의 로그인 정보를 다시 입력하세요. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=이(가) SmartThings에서 연결 해제되었습니다. 로그인 정보가 변경되었거나 유실되었습니다. Ecobee (연결) 스마트앱에서 계정의 로그인 정보를 다시 입력하세요. '''Your Ecobee thermostat '''=Ecobee 온도조절기 '''Select your ecobee devices'''=ecobee 기기 선택 '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=ecobee 계정에서 사용할 수 있는 온도조절기를 추가하거나 삭제하려면 아래를 누르세요. 선택된 온도조절기를 SmartThings에 연결합니다. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties b/smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties index 85a2b38539a..173ef4e7e3c 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/nl-NL.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Er kan geen verbinding worden gemaakt. '''Click 'Done' to return to the menu.'''=Klik op Done (Gereed) om terug te gaan naar het menu. '''is connected to SmartThings'''=is verbonden met SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=-verbinding met SmartThings is verbroken, omdat de inloggegevens zijn gewijzigd of verloren zijn gegaan. Ga naar de Ecobee (Connect) SmartApp en voer de inloggegevens voor uw account opnieuw in. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=-verbinding met SmartThings is verbroken, omdat de inloggegevens zijn gewijzigd of verloren zijn gegaan. Ga naar de Ecobee (Connect) SmartApp en voer de inloggegevens voor uw account opnieuw in. '''Your Ecobee thermostat '''=Uw Ecobee-thermostaat '''Select your ecobee devices'''=Selecteer uw ecobee-apparaten '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tik hieronder om thermostaten die beschikbaar zijn in uw ecobee-account, toe te voegen of te verwijderen. Geselecteerde thermostaten maken verbinding met SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties b/smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties index 53ea6bb3a55..b38993c2ba0 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/no-NO.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Kunne ikke opprette tilkoblingen! '''Click 'Done' to return to the menu.'''=Klikk på Done (Ferdig) for å gå tilbake til menyen. '''is connected to SmartThings'''=er koblet til SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=er koblet fra SmartThings fordi tilgangsinformasjonen ble endret eller mistet. Gå til Ecobee (Connect) SmartApp, og angi påloggingsinformasjonen for kontoen på nytt. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=er koblet fra SmartThings fordi tilgangsinformasjonen ble endret eller mistet. Gå til Ecobee (Connect) SmartApp, og angi påloggingsinformasjonen for kontoen på nytt. '''Your Ecobee thermostat '''=Ecobee-termostaten '''Select your ecobee devices'''=Velg ecobee-enhetene dine '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Trykk nedenfor for å legge til eller fjerne termostater som er tilgjengelige i ecobee-kontoen din. Valgte termostater blir koblet til SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties b/smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties index be9eddb0dcd..b5c48ef48ac 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/pl-PL.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Nie można ustanowić połączenia. '''Click 'Done' to return to the menu.'''=Kliknij opcję „Done” (Gotowe), aby powrócić do menu. '''is connected to SmartThings'''=jest połączony ze SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=jest odłączony od SmartThings, ponieważ poświadczenie dostępu zostało zmienione lub utracone. Przejdź do aplikacji Ecobee (Connect) SmartApp i wprowadź ponownie poświadczenia logowania konta. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=jest odłączony od SmartThings, ponieważ poświadczenie dostępu zostało zmienione lub utracone. Przejdź do aplikacji Ecobee (Connect) SmartApp i wprowadź ponownie poświadczenia logowania konta. '''Your Ecobee thermostat '''=Termostat Ecobee '''Select your ecobee devices'''=Wybierz urządzenia ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Dotknij poniżej, aby dodać lub usunąć termostaty dostępne na koncie ecobee. Wybrane termostaty zostaną połączone ze SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties index 5005e056077..cedf11f9b31 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/pt-BR.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Não foi possível estabelecer a conexão! '''Click 'Done' to return to the menu.'''=Clique em 'Done' (Concluído) para retornar ao menu. '''is connected to SmartThings'''=está conectado ao SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=foi desconectado do SmartThings, pois a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e insira novamente suas credenciais de acesso à conta. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=foi desconectado do SmartThings, pois a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e insira novamente suas credenciais de acesso à conta. '''Your Ecobee thermostat '''=Seu termostato Ecobee '''Select your ecobee devices'''=Selecionar seus aparelhos ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toque abaixo para adicionar ou remover os termostatos disponíveis na sua conta ecobee. Os termostatos selecionados serão conectados ao SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties b/smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties index ca8626b1583..d70f944e1e2 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/pt-PT.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Não foi possível estabelecer a ligação! '''Click 'Done' to return to the menu.'''=Clique em "Done" (Concluir) para regressar ao menu. '''is connected to SmartThings'''=está ligado ao SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=foi desligado do SmartThings, porque a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e introduza novamente as suas credenciais de início de sessão na conta. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=foi desligado do SmartThings, porque a credencial de acesso foi alterada ou perdida. Vá para Ecobee (Connect) SmartApp e introduza novamente as suas credenciais de início de sessão na conta. '''Your Ecobee thermostat '''=O seu termóstato Ecobee '''Select your ecobee devices'''=Seleccionar os seus dispositivos ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Toque abaixo para adicionar ou remover termóstatos disponíveis na sua conta ecobee. Os termóstatos seleccionados irão ligar-se ao SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties index c115c1be832..d552f704983 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/ro-RO.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Nu a putut fi stabilită conexiunea! '''Click 'Done' to return to the menu.'''=Faceți clic pe „Done” (Efectuat) pentru a reveni la meniu. '''is connected to SmartThings'''=este conectat la SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=este deconectat de la SmartThings, deoarece acreditările de acces au fost schimbate sau pierdute. Accesați aplicația Ecobee (Connect) SmartApp și reintroduceți acreditările de conectare la cont. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=este deconectat de la SmartThings, deoarece acreditările de acces au fost schimbate sau pierdute. Accesați aplicația Ecobee (Connect) SmartApp și reintroduceți acreditările de conectare la cont. '''Your Ecobee thermostat '''=Termostatul dvs. Ecobee '''Select your ecobee devices'''=Selectați dispozitivele dvs. ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Atingeți mai jos pentru a adăuga sau elimina termostate disponibile în contul dvs. ecobee. Termostatele selectate se vor conecta la SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties b/smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties index a076a18d699..bfa4b083b0e 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/ru-RU.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Не удалось установить соединение! '''Click 'Done' to return to the menu.'''=Чтобы вернуться в меню, нажмите «Готово». '''is connected to SmartThings'''=подключено к SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=отключено от SmartThings, поскольку данные для доступа были изменены или потеряны. Перейдите в Ecobee (Подключить) SmartApp и повторно введите регистрационные данные своей учетной записи. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=отключено от SmartThings, поскольку данные для доступа были изменены или потеряны. Перейдите в Ecobee (Подключить) SmartApp и повторно введите регистрационные данные своей учетной записи. '''Your Ecobee thermostat '''=Ваш термостат Ecobee '''Select your ecobee devices'''=Выберите свои устройства ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Чтобы добавить или удалить доступные термостаты в учетной записи ecobee, коснитесь ниже. Выбранные термостаты будут подключены к SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties index 99f1060e66b..e0e9fb1ced3 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/sk-SK.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Nepodarilo sa nadviazať spojenie. '''Click 'Done' to return to the menu.'''=Kliknutím na tlačidlo Done (Hotovo) sa vráťte do menu. '''is connected to SmartThings'''=je pripojený k systému SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=je odpojený od systému SmartThings, pretože prístupové poverenia boli zmenené alebo stratené. Prejdite do aplikácie Ecobee (Connect) SmartApp a znova zadajte prihlasovacie poverenia pre konto. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=je odpojený od systému SmartThings, pretože prístupové poverenia boli zmenené alebo stratené. Prejdite do aplikácie Ecobee (Connect) SmartApp a znova zadajte prihlasovacie poverenia pre konto. '''Your Ecobee thermostat '''=Váš termostat Ecobee '''Select your ecobee devices'''=Vyberte svoje zariadenia ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Ťuknutím nižšie môžete pridať alebo odstrániť termostaty dostupné vo vašom konte ecobee. Vybraté termostaty sa pripoja k systému SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties index 6e1004ad402..c4b71c54066 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/sl-SI.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Povezave ni bilo mogoče vzpostaviti! '''Click 'Done' to return to the menu.'''=Kliknite »Done« (Končano), da se vrnete v meni. '''is connected to SmartThings'''=je povezan s storitvijo SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=ni povezan s storitvijo SmartThings, ker so bile poverilnice za dostop spremenjene ali izgubljene. Pojdite v aplikacijo Ecobee (Connect) SmartApp in znova vnesite poverilnice za prijavo v račun. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=ni povezan s storitvijo SmartThings, ker so bile poverilnice za dostop spremenjene ali izgubljene. Pojdite v aplikacijo Ecobee (Connect) SmartApp in znova vnesite poverilnice za prijavo v račun. '''Your Ecobee thermostat '''=Vaš termostat Ecobee '''Select your ecobee devices'''=Izberite naprave ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Pritisnite spodaj, da dodate ali odstranite termostate, ki so na voljo v vašem računu ecobee. Izbrani termostati se bodo povezali s storitvijo SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties index 5dc3421e195..d92f42c06bf 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/sq-AL.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Lidhja nuk u vendos dot! '''Click 'Done' to return to the menu.'''=Kliko mbi ‘Done’ (U krye) për t’u kthyer në meny. '''is connected to SmartThings'''=është lidhur me SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=është shkëputur nga SmartThings, sepse kredenciali i aksesit ka ndryshuar ose ka humbur. Shko te Ecobee (Connect) SmartApp dhe futi sërish kredencialet e logimit në llogari. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=është shkëputur nga SmartThings, sepse kredenciali i aksesit ka ndryshuar ose ka humbur. Shko te Ecobee (Connect) SmartApp dhe futi sërish kredencialet e logimit në llogari. '''Your Ecobee thermostat '''=Termostati yt Ecobee '''Select your ecobee devices'''=Përzgjidh pajisjet e tua ecobee '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Trokit më poshtë për të shtuar ose hequr termostate që gjenden në llogarinë tënde ecobee. Termostatet e përzgjedhura do të lidhen me SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties index c2f13d6ae0d..2ed4545e50c 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/sr-RS.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Veza nije uspostavljena! '''Click 'Done' to return to the menu.'''=Kliknite na „Done” (Gotovo) da biste se vratili na meni. '''is connected to SmartThings'''=je povezan na SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=je prekinuo vezu sa aplikacijom SmartThings zato što su akreditivi za pristup promenjeni ili izgubljeni. Idite na aplikaciju Ecobee (Connect) SmartApp i ponovo unesite akreditive za prijavljivanje na nalog. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=je prekinuo vezu sa aplikacijom SmartThings zato što su akreditivi za pristup promenjeni ili izgubljeni. Idite na aplikaciju Ecobee (Connect) SmartApp i ponovo unesite akreditive za prijavljivanje na nalog. '''Your Ecobee thermostat '''=Vaš Ecobee termostat '''Select your ecobee devices'''=Izaberite ecobee uređaje '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Kucnite ispod da biste dodali ili uklonili dostupne termostate na ecobee nalogu. Izabrani termostati će se povezati na SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties b/smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties index 67081695813..ea957914439 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/sv-SE.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Det gick inte att upprätta anslutningen! '''Click 'Done' to return to the menu.'''=Klicka på Done (Klart) för att återgå till menyn. '''is connected to SmartThings'''=är ansluten till SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=är frånkopplad från SmartThings, eftersom inloggningsuppgifterna har ändrats eller gått förlorade. Starta Ecobee (Connect) SmartApp och ange kontots inloggningsuppgifter igen. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=är frånkopplad från SmartThings, eftersom inloggningsuppgifterna har ändrats eller gått förlorade. Starta Ecobee (Connect) SmartApp och ange kontots inloggningsuppgifter igen. '''Your Ecobee thermostat '''=Din Ecobee-termostat '''Select your ecobee devices'''=Välj dina ecobee-enheter '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=Tryck nedan om du vill lägga till eller ta bort termostater som är tillgängliga i ditt ecobee-konto. De valda termostaterna ansluter till SmartThings. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties b/smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties index 068b69896c7..57a2f36f35b 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/th-TH.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=ไม่สามารถสร้างการเชื่อมต่อได้! '''Click 'Done' to return to the menu.'''=คลิก 'เสร็จสิ้น' เพื่อกลับไปยังเมนู '''is connected to SmartThings'''={{deviceName}} เชื่อมต่อกับ SmartThings แล้ว -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''={{deviceName}} ถูกตัดการเชื่อมต่อจาก SmartThings เนื่องจากข้อมูลการเข้าถึงถูกเปลี่ยนแปลงหรือหายไป กรุณาไปที่ Ecobee (การเชื่อมต่อ) SmartApp และใส่ข้อมูลยืนยันตัวตนการเข้าสู่บัญชีผู้ใช้ของคุณอีกครั้ง +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''={{deviceName}} ถูกตัดการเชื่อมต่อจาก SmartThings เนื่องจากข้อมูลการเข้าถึงถูกเปลี่ยนแปลงหรือหายไป กรุณาไปที่ Ecobee (การเชื่อมต่อ) SmartApp และใส่ข้อมูลยืนยันตัวตนการเข้าสู่บัญชีผู้ใช้ของคุณอีกครั้ง '''Your Ecobee thermostat '''=ตัวควบคุมอุณหภูมิ Ecobee ของคุณ '''Select your ecobee devices'''=เลือกอุปกรณ์ ecobee ของคุณ '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=แตะด้านล่างเพื่อเพิ่มหรือลบตัวควบคุมอุณหภูมิที่พร้อมใช้งานในบัญชี ecobee ของคุณ ตัวควบคุมอุณหภูมิที่เลือกจะเชื่อมต่อกับ SmartThings diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties b/smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties index c5b80f32dd6..59f4e905ff3 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/tr-TR.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=Bağlantı kurulamadı! '''Click 'Done' to return to the menu.'''=Menüye dönmek için 'Bitti' öğesine tıklayın. '''is connected to SmartThings'''={{cihazİsmi}} SmartThings'e bağlandı -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=Erişim kimlik doğruları değiştirildiğinden veya kaybolduğundan {{cihazİsmi}} ile SmartThings arasındaki bağlantı kesildi. Lütfen Ecobee (Connect) SmartApp'e gidin ve hesabınızın oturum açma kimlik bilgilerini tekrar girin. +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=Erişim kimlik doğruları değiştirildiğinden veya kaybolduğundan {{cihazİsmi}} ile SmartThings arasındaki bağlantı kesildi. Lütfen Ecobee (Connect) SmartApp'e gidin ve hesabınızın oturum açma kimlik bilgilerini tekrar girin. '''Your Ecobee thermostat '''=Ecobee termostatınız '''Select your ecobee devices'''=ecobee Cihazlarınızı seçin '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=ecobee hesabınızdaki kullanılabilir termostatları eklemek veya kaldırmak için aşağıya dokunun. Seçilen termostatlar SmartThings'e bağlanır. diff --git a/smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties b/smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties index 9694b09b9de..a927eb82b41 100644 --- a/smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties +++ b/smartapps/smartthings/ecobee-connect.src/i18n/zh-CN.properties @@ -16,7 +16,7 @@ '''The connection could not be established!'''=无法建立连接! '''Click 'Done' to return to the menu.'''=单击“完成”返回菜单。 '''is connected to SmartThings'''=已连接至 SmartThings -'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials.'''=已从 SmartThings 断开,因为访问凭据已更改或丢失。请转到 Ecobee (连接) SmartApp,然后重新输入您的帐户登录凭据。 +'''is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) Linked Service and re-enter your account login credentials.'''=已从 SmartThings 断开,因为访问凭据已更改或丢失。请转到 Ecobee (连接) SmartApp,然后重新输入您的帐户登录凭据。 '''Your Ecobee thermostat '''=您的 Ecobee 恒温器 '''Select your ecobee devices'''=选择您的 ecobee 设备 '''Tap below to add or remove thermostats available in your ecobee account. Selected thermostats will connect to SmartThings.'''=点击下方可添加或删除 ecobee 帐户中的恒温器。选定的恒温器将连接到 SmartThings。 diff --git a/smartapps/smartthings/ifttt.src/ifttt.groovy b/smartapps/smartthings/ifttt.src/ifttt.groovy index f3bd91b4770..32d8a44b8ee 100644 --- a/smartapps/smartthings/ifttt.src/ifttt.groovy +++ b/smartapps/smartthings/ifttt.src/ifttt.groovy @@ -96,7 +96,7 @@ mappings { } def installed() { - log.debug settings + //log.debug settings } def updated() { @@ -109,11 +109,11 @@ def updated() { state.remove(device.id) unsubscribe(device) } - log.debug settings + //log.debug settings } def list() { - log.debug "[PROD] list, params: ${params}" + //log.debug "[PROD] list, params: ${params}" def type = params.deviceType settings[type]?.collect{deviceItem(it)} ?: [] } @@ -136,7 +136,7 @@ def update() { def device = settings[type]?.find { it.id == params.id } def command = data.command - log.debug "[PROD] update, params: ${params}, request: ${data}, devices: ${devices*.id}" + //log.debug "[PROD] update, params: ${params}, request: ${data}, devices: ${devices*.id}" if (!device) { httpError(404, "Device not found") @@ -201,7 +201,7 @@ def show() { def devices = settings[type] def device = devices.find { it.id == params.id } - log.debug "[PROD] show, params: ${params}, devices: ${devices*.id}" + //log.debug "[PROD] show, params: ${params}, devices: ${devices*.id}" if (!device) { httpError(404, "Device not found") } @@ -222,13 +222,13 @@ def addSubscription() { def callbackUrl = data.callbackUrl def device = devices.find { it.id == deviceId } - log.debug "[PROD] addSubscription, params: ${params}, request: ${data}, device: ${device}" + //log.debug "[PROD] addSubscription, params: ${params}, request: ${data}, device: ${device}" if (device) { log.debug "Adding switch subscription " + callbackUrl state[deviceId] = [callbackUrl: callbackUrl] subscribe(device, attribute, deviceHandler) } - log.info state + //log.info state } @@ -238,13 +238,13 @@ def removeSubscription() { def deviceId = params.id def device = devices.find { it.id == deviceId } - log.debug "[PROD] removeSubscription, params: ${params}, request: ${data}, device: ${device}" + //log.debug "[PROD] removeSubscription, params: ${params}, request: ${data}, device: ${device}" if (device) { log.debug "Removing $device.displayName subscription" state.remove(device.id) unsubscribe(device) } - log.info state + //log.info state } def deviceHandler(evt) { @@ -255,7 +255,7 @@ def deviceHandler(evt) { log.debug "[PROD IFTTT] Event data successfully posted" } } catch (groovyx.net.http.ResponseParseException e) { - log.debug("Error parsing ifttt payload ${e}") + log.error("Error parsing ifttt payload ${e}") } } else { log.debug "[PROD] No subscribed device found" diff --git a/smartapps/smartthings/lifx-connect.src/i18n/ar-AE.properties b/smartapps/smartthings/lifx-connect.src/i18n/ar-AE.properties deleted file mode 100644 index 54337ca9dbd..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/ar-AE.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=يتيح لك استخدام مصابيح LIFX الذكية من خلال SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=النقر لإدخال بيانات اعتماد LIFX -'''Connect to LIFX'''=الاتصال بـ LIFX -'''Tap here to connect your LIFX account'''=النقر هنا لتوصيل حساب LIFX -'''Connect to LIFX'''=الاتصال بـ LIFX -'''Select your location'''=تحديد موقعك -'''Select location ({{count}} found)'''=تحديد الموقع (‎{{count}} found) -'''Your LIFX Account is now connected to SmartThings!'''=حساب LIFX متصل الآن بـ SmartThings! -'''Click 'Done' to finish setup.'''=انقر فوق ”تم“ لإنهاء الإعداد. -'''The connection could not be established!'''=يتعذر إنشاء الاتصال! -'''Click 'Done' to return to the menu.'''=انقر فوق ”تم“ للعودة إلى القائمة. -'''Your LIFX Account is already connected to SmartThings!'''=حساب LIFX متصل بالفعل بـ SmartThings! -'''Click 'Done' to finish setup.'''=انقر فوق ”تم“ لإنهاء الإعداد. -'''SmartThings Connection'''=اتصال SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=ستتم إضافة الأجهزة تلقائياً من حساب LIFX. لإضافة الأجهزة أو حذفها، يرجى استخدام التطبيق الرسمي لـ LIFX -'''Set for specific mode(s)'''=ضبط لوضع محدد (أوضاع محددة) -'''Assign a name'''=تعيين اسم -'''Tap to set'''=النقر للضبط -'''Phone'''=رقم الهاتف -'''Which?'''=أي مستشعر؟ -'''Add a name'''=إضافة اسم -'''Tap to choose'''=النقر للاختيار -'''Choose an icon'''=اختيار رمز -'''Next page'''=الصفحة التالية -'''Text'''=النص -'''Number'''=الرقم diff --git a/smartapps/smartthings/lifx-connect.src/i18n/bg-BG.properties b/smartapps/smartthings/lifx-connect.src/i18n/bg-BG.properties deleted file mode 100644 index 303d7552694..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/bg-BG.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Позволява да използвате интелигентни ел. крушки LIFX със SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Докоснете за въвеждане на идентификационни данни за LIFX -'''Connect to LIFX'''=Свързване към LIFX -'''Tap here to connect your LIFX account'''=Докоснете тук за свързване на вашия LIFX акаунт -'''Connect to LIFX'''=Свързване към LIFX -'''Select your location'''=Избор на местоположение -'''Select location ({{count}} found)'''=Избор на местоположение ({{count}} са намерени) -'''Your LIFX Account is now connected to SmartThings!'''=Вашият LIFX акаунт вече е свързан към SmartThings! -'''Click 'Done' to finish setup.'''=Щракнете върху Done (Готово), за да завършите настройката. -'''The connection could not be established!'''=Връзката не може да се осъществи! -'''Click 'Done' to return to the menu.'''=Щракнете върху Done (Готово), за да се върнете към менюто. -'''Your LIFX Account is already connected to SmartThings!'''=Вашият LIFX акаунт вече е свързан към SmartThings! -'''Click 'Done' to finish setup.'''=Щракнете върху Done (Готово), за да завършите настройката. -'''SmartThings Connection'''=Свързване на SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Устройствата ще се добавят автоматично от вашия акаунт в LIFX. За да добавите или изтриете устройства, използвайте официалното приложение на LIFX. -'''Set for specific mode(s)'''=Зададено за конкретни режими -'''Assign a name'''=Назначаване на име -'''Tap to set'''=Докосване за задаване -'''Phone'''=Телефонен номер -'''Which?'''=Кое? -'''Add a name'''=Добавяне на име -'''Tap to choose'''=Докосване за избор -'''Choose an icon'''=Избор на икона -'''Next page'''=Следваща страница -'''Text'''=Текст -'''Number'''=Номер diff --git a/smartapps/smartthings/lifx-connect.src/i18n/ca-ES.properties b/smartapps/smartthings/lifx-connect.src/i18n/ca-ES.properties deleted file mode 100644 index 4c66e870185..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/ca-ES.properties +++ /dev/null @@ -1,11 +0,0 @@ -'''Set for specific mode(s)'''=Definir para modos específicos -'''Assign a name'''=Asignar un nome -'''Tap to set'''=Toca aquí para definir -'''Phone'''=Número de teléfono -'''Which?'''=Cal? -'''Add a name'''=Engade un nome -'''Tap to choose'''=Toca para escoller -'''Choose an icon'''=Escolle unha icona -'''Next page'''=Páxina seguinte -'''Text'''=Texto -'''Number'''=Número diff --git a/smartapps/smartthings/lifx-connect.src/i18n/cs-CZ.properties b/smartapps/smartthings/lifx-connect.src/i18n/cs-CZ.properties deleted file mode 100644 index 1b60a923e5b..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/cs-CZ.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Umožní vám použít inteligentní žárovky LIFX se systémem SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Klepněte a zadejte přihlašovací údaje LIFX -'''Connect to LIFX'''=Připojit k LIFX -'''Tap here to connect your LIFX account'''=Klepnutím sem se připojíte k účtu LIFX -'''Connect to LIFX'''=Připojit k LIFX -'''Select your location'''=Vyberte vaši polohu -'''Select location ({{count}} found)'''=Vyberte polohu (nalezeno {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Účet LIFX Account je nyní připojen k systému SmartThings! -'''Click 'Done' to finish setup.'''=Dokončete nastavení klepnutím na tlačítko „Done“ (Hotovo). -'''The connection could not be established!'''=Připojení nelze navázat! -'''Click 'Done' to return to the menu.'''=Klepnutím na tlačítko „Done“ (Hotovo) se vrátíte do menu. -'''Your LIFX Account is already connected to SmartThings!'''=Účet LIFX Account je již připojen k systému SmartThings! -'''Click 'Done' to finish setup.'''=Dokončete nastavení klepnutím na tlačítko „Done“ (Hotovo). -'''SmartThings Connection'''=Připojení SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Zařízení budou automaticky přidána z účtu LIFX. K přidávání nebo odstraňování zařízení použijte oficiální aplikaci LIFX. -'''Set for specific mode(s)'''=Nastavit pro konkrétní režimy -'''Assign a name'''=Přiřadit název -'''Tap to set'''=Nastavte klepnutím -'''Phone'''=Telefonní číslo -'''Which?'''=Který? -'''Add a name'''=Přidejte název -'''Tap to choose'''=Klepnutím zvolte -'''Choose an icon'''=Zvolte ikonu -'''Next page'''=Další stránka -'''Text'''=Text -'''Number'''=Číslo diff --git a/smartapps/smartthings/lifx-connect.src/i18n/da-DK.properties b/smartapps/smartthings/lifx-connect.src/i18n/da-DK.properties deleted file mode 100644 index 6420c58a573..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/da-DK.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Giver dig mulighed for at bruge LIFX-smartpærer sammen med SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Tryk for at indtaste LIFX-legitimationsoplysninger -'''Connect to LIFX'''=Forbind med LIFX -'''Tap here to connect your LIFX account'''=Tryk her for at forbinde din LIFX-konto -'''Connect to LIFX'''=Forbind med LIFX -'''Select your location'''=Vælg din placering -'''Select location ({{count}} found)'''=Vælg placering ({{count}} fundet) -'''Your LIFX Account is now connected to SmartThings!'''=Din LIFX-konto er nu forbundet med SmartThings! -'''Click 'Done' to finish setup.'''=Klik på “Done” (Udført) for at afslutte konfigurationen. -'''The connection could not be established!'''=Der kunne ikke oprettes forbindelse! -'''Click 'Done' to return to the menu.'''=Klik på “Done” (Udført) for at vende tilbage til menuen. -'''Your LIFX Account is already connected to SmartThings!'''=Din LIFX-konto er allerede forbundet med SmartThings! -'''Click 'Done' to finish setup.'''=Klik på “Done” (Udført) for at afslutte konfigurationen. -'''SmartThings Connection'''=SmartThings-forbindelse -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Enheder vil blive tilføjet automatisk fra din LIFX-konto. Hvis du vil tilføje eller slette enheder, skal du bruge den officielle LIFX-app. -'''Set for specific mode(s)'''=Indstil til bestemt(e) tilstand(e) -'''Assign a name'''=Tildel et navn -'''Tap to set'''=Tryk for at indstille -'''Phone'''=Telefonnummer -'''Which?'''=Hvilken? -'''Add a name'''=Tilføj et navn -'''Tap to choose'''=Tryk for at vælge -'''Choose an icon'''=Vælg et ikon -'''Next page'''=Næste side -'''Text'''=Tekst -'''Number'''=Nummer diff --git a/smartapps/smartthings/lifx-connect.src/i18n/de-DE.properties b/smartapps/smartthings/lifx-connect.src/i18n/de-DE.properties deleted file mode 100644 index 6f35ba1bef7..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/de-DE.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Ermöglicht die Verwendung intelligenter Glühbirnen von LIFX mit SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Tippen, um LIFX-Zugangsdaten einzugeben -'''Connect to LIFX'''=Mit LIFX verbinden -'''Tap here to connect your LIFX account'''=Hier tippen, um Ihr LIFX-Konto zu verbinden. -'''Connect to LIFX'''=Mit LIFX verbinden -'''Select your location'''=Ihren Standort auswählen -'''Select location ({{count}} found)'''=Standortauswahl ({{count}} gefunden) -'''Your LIFX Account is now connected to SmartThings!'''=Ihr LIFX-Konto ist jetzt mit SmartThings verbunden! -'''Click 'Done' to finish setup.'''=Klicken Sie auf „Done“ (OK), um die Einrichtung abzuschließen. -'''The connection could not be established!'''=Es konnte keine Verbindung hergestellt werden! -'''Click 'Done' to return to the menu.'''=Klicken Sie auf „Done“ (OK), um zum Menü zurückzukehren. -'''Your LIFX Account is already connected to SmartThings!'''=Ihr LIFX-Konto ist bereits mit SmartThings verbunden! -'''Click 'Done' to finish setup.'''=Klicken Sie auf „Done“ (OK), um die Einrichtung abzuschließen. -'''SmartThings Connection'''=SmartThings-Verbindung -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Geräte werden automatisch aus Ihrem LIFX-Konto hinzugefügt. Verwenden Sie zum Hinzufügen oder Löschen von Geräten bitte die offizielle LIFX-App. -'''Set for specific mode(s)'''=Für bestimmte Modi festlegen -'''Assign a name'''=Einen Namen zuweisen -'''Tap to set'''=Zum Festlegen tippen -'''Phone'''=Telefonnummer -'''Which?'''=Welcher? -'''Add a name'''=Einen Namen hinzufügen -'''Tap to choose'''=Zur Auswahl tippen -'''Choose an icon'''=Symbolauswahl -'''Next page'''=Nächste Seite -'''Text'''=Text -'''Number'''=Nummer diff --git a/smartapps/smartthings/lifx-connect.src/i18n/el-GR.properties b/smartapps/smartthings/lifx-connect.src/i18n/el-GR.properties deleted file mode 100644 index 9f19740f0c0..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/el-GR.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Σας επιτρέπει να χρησιμοποιείτε έξυπνους λαμπτήρες LIFX με το SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Πατήστε για να καταχωρήσετε διαπιστευτήρια LIFX -'''Connect to LIFX'''=Σύνδεση στο LIFX -'''Tap here to connect your LIFX account'''=Πατήστε εδώ για να συνδέσετε το λογαριασμό σας LIFX -'''Connect to LIFX'''=Σύνδεση στο LIFX -'''Select your location'''=Επιλέξτε την τοποθεσία σας -'''Select location ({{count}} found)'''=Επιλογή τοποθεσίας (βρέθηκαν {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Ο λογαριασμός σας στο LIFX έχει τώρα συνδεθεί στο SmartThings! -'''Click 'Done' to finish setup.'''=Πατήστε "Done" (Τέλος) για να ολοκληρωθεί η ρύθμιση. -'''The connection could not be established!'''=Δεν ήταν δυνατή η δημιουργία σύνδεσης! -'''Click 'Done' to return to the menu.'''=Κάντε κλικ στο "Done" (Τέλος) για να επιστρέψετε στο μενού. -'''Your LIFX Account is already connected to SmartThings!'''=Ο λογαριασμός σας στο LIFX έχει ήδη συνδεθεί στο SmartThings! -'''Click 'Done' to finish setup.'''=Πατήστε "Done" (Τέλος) για να ολοκληρωθεί η ρύθμιση. -'''SmartThings Connection'''=Σύνδεση SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Οι συσκευές θα προστεθούν αυτόματα από το λογαριασμό σας LIFX. Για να προσθέσετε ή να διαγράψετε συσκευές, χρησιμοποιήστε την επίσημη εφαρμογή της LIFX. -'''Set for specific mode(s)'''=Ορισμός για συγκεκριμένες λειτουργίες -'''Assign a name'''=Αντιστοίχιση ονόματος -'''Tap to set'''=Πατήστε για ρύθμιση -'''Phone'''=Αριθμός τηλεφώνου -'''Which?'''=Ποιος; -'''Add a name'''=Προσθέστε ένα όνομα -'''Tap to choose'''=Πατήστε για επιλογή -'''Choose an icon'''=Επιλέξτε ένα εικονίδιο -'''Next page'''=Επόμενη σελίδα -'''Text'''=Κείμενο -'''Number'''=Αριθμός diff --git a/smartapps/smartthings/lifx-connect.src/i18n/en-GB.properties b/smartapps/smartthings/lifx-connect.src/i18n/en-GB.properties deleted file mode 100644 index 621f89a6858..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/en-GB.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Allows you to use LIFX smart light bulbs with SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Tap to enter LIFX credentials -'''Connect to LIFX'''=Connect to LIFX -'''Tap here to connect your LIFX account'''=Tap here to connect your LIFX account -'''Connect to LIFX'''=Connect to LIFX -'''Select your location'''=Select your location -'''Select location ({{count}} found)'''=Select location ({{count}} found) -'''Your LIFX Account is now connected to SmartThings!'''=Your LIFX Account is now connected to SmartThings! -'''Click 'Done' to finish setup.'''=Click ’Done’ to exit setup. -'''The connection could not be established!'''=The connection could not be established! -'''Click 'Done' to return to the menu.'''=Click ’Done’ to return to the menu. -'''Your LIFX Account is already connected to SmartThings!'''=Your LIFX Account is already connected to SmartThings! -'''Click 'Done' to finish setup.'''=Click ’Done’ to finish setup. -'''SmartThings Connection'''=SmartThings Connection -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Devices will be added automatically from your LIFX account. To add or delete devices, please use the official LIFX app. -'''Set for specific mode(s)'''=Set for specific mode(s) -'''Assign a name'''=Assign a name -'''Tap to set'''=Tap to set -'''Phone'''=Phone -'''Which?'''=Which? -'''Add a name'''=Add a name -'''Tap to choose'''=Tap to choose -'''Choose an icon'''=Choose an icon -'''Next page'''=Next page -'''Text'''=Text -'''Number'''=Number diff --git a/smartapps/smartthings/lifx-connect.src/i18n/en-US.properties b/smartapps/smartthings/lifx-connect.src/i18n/en-US.properties deleted file mode 100644 index 3ad2f1c7703..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/en-US.properties +++ /dev/null @@ -1,11 +0,0 @@ -'''Set for specific mode(s)'''=Set for specific mode(s) -'''Assign a name'''=Assign a name -'''Tap to set'''=Tap to set -'''Phone'''=Phone -'''Which?'''=Which? -'''Add a name'''=Add a name -'''Tap to choose'''=Tap to choose -'''Choose an icon'''=Choose an icon -'''Next page'''=Next page -'''Text'''=Text -'''Number'''=Number diff --git a/smartapps/smartthings/lifx-connect.src/i18n/es-ES.properties b/smartapps/smartthings/lifx-connect.src/i18n/es-ES.properties deleted file mode 100644 index 0639ff0e991..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/es-ES.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Le permite utilizar bombillas de luz inteligente LIFX con SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Pulsar para introducir credenciales de LIFX -'''Connect to LIFX'''=Conectar a LIFX -'''Tap here to connect your LIFX account'''=Pulsar aquí para conectar la cuenta LIFX -'''Connect to LIFX'''=Conectar a LIFX -'''Select your location'''=Seleccionar ubicación -'''Select location ({{count}} found)'''=Seleccionar ubicación ({{count}} encontrado) -'''Your LIFX Account is now connected to SmartThings!'''=¡Su cuenta de LIFX ya está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración. -'''The connection could not be established!'''=¡No se ha podido establecer la conexión! -'''Click 'Done' to return to the menu.'''=Haga clic en “Done” (Hecho) para volver al menú. -'''Your LIFX Account is already connected to SmartThings!'''=¡Su cuenta de LIFX ya está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en “Done” (Hecho) para finalizar la configuración. -'''SmartThings Connection'''=Conexión de SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Los dispositivos se añadirán automáticamente desde tu cuenta de LIFX. Para añadir o eliminar dispositivos, usa la aplicación oficial de LIFX. -'''Set for specific mode(s)'''=Establecer para modo(s) específico(s) -'''Assign a name'''=Asignar un nombre -'''Tap to set'''=Pulsa para configurar -'''Phone'''=Número de teléfono -'''Which?'''=¿Qué? -'''Add a name'''=Añadir un nombre -'''Tap to choose'''=Pulsar para elegir -'''Choose an icon'''=Elegir un icono -'''Next page'''=Página siguiente -'''Text'''=Texto -'''Number'''=Número diff --git a/smartapps/smartthings/lifx-connect.src/i18n/es-MX.properties b/smartapps/smartthings/lifx-connect.src/i18n/es-MX.properties deleted file mode 100644 index c629e078dbb..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/es-MX.properties +++ /dev/null @@ -1,11 +0,0 @@ -'''Set for specific mode(s)'''=Definir para modos específicos -'''Assign a name'''=Asignar un nombre -'''Tap to set'''=Pulsar para definir -'''Phone'''=Número de teléfono -'''Which?'''=¿Cuál? -'''Add a name'''=Añadir un nombre -'''Tap to choose'''=Pulsar para elegir -'''Choose an icon'''=Elegir un ícono -'''Next page'''=Página siguiente -'''Text'''=Texto -'''Number'''=Número diff --git a/smartapps/smartthings/lifx-connect.src/i18n/es-US.properties b/smartapps/smartthings/lifx-connect.src/i18n/es-US.properties deleted file mode 100644 index 3c686befa6b..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/es-US.properties +++ /dev/null @@ -1,16 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Le permite usar las bombillas inteligentes LIFX con SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Pulse para introducir las credenciales de LIFX -'''Connect to LIFX'''=Conectar a LIFX -'''Tap here to connect your LIFX account'''=Pulse aquí para conectar su cuenta de LIFX -'''Connect to LIFX'''=Conectar a LIFX -'''Select your location'''=Seleccione su ubicación -'''Select location ({{count}} found)'''=Seleccionar ubicación (hay {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=¡Su cuenta de LIFX ahora está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en 'Done' ('Listo') para finalizar la configuración. -'''The connection could not be established!'''=¡No fue posible establecer la conexión! -'''Click 'Done' to return to the menu.'''=Haga clic en 'Done' ('Listo') para volver al menú. -'''Your LIFX Account is already connected to SmartThings!'''=¡Su cuenta de LIFX ya está conectada a SmartThings! -'''Click 'Done' to finish setup.'''=Haga clic en 'Done' ('Listo') para finalizar la configuración. -'''SmartThings Connection'''=Conexión de SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Los dispositivos se añadirán automáticamente desde tu cuenta de LIFX. Para añadir o eliminar dispositivos, usa la aplicación oficial de LIFX. diff --git a/smartapps/smartthings/lifx-connect.src/i18n/et-EE.properties b/smartapps/smartthings/lifx-connect.src/i18n/et-EE.properties deleted file mode 100644 index e8f9522c0f3..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/et-EE.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Võimaldab kasutada LIFXi nutikaid lambipirne teenusega SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Toksake, et sisestada teenuse LIFX volitused -'''Connect to LIFX'''=Loo ühendus teenusega LIFX -'''Tap here to connect your LIFX account'''=Toksake siia, et luua ühendus oma LIFXi kontoga -'''Connect to LIFX'''=Loo ühendus teenusega LIFX -'''Select your location'''=Valige oma asukoht -'''Select location ({{count}} found)'''=Valige asukoht ({{count}} found) -'''Your LIFX Account is now connected to SmartThings!'''=Teie LIFXi konto on nüüd ühendatud teenusega SmartThings! -'''Click 'Done' to finish setup.'''=Klõpsake valikut Valmis, et seadistamine lõpule viia. -'''The connection could not be established!'''=Ühenduse loomine nurjus! -'''Click 'Done' to return to the menu.'''=Klõpsake valikut Valmis, et naasta menüüsse. -'''Your LIFX Account is already connected to SmartThings!'''=Teie LIFXi konto on juba ühendatud teenusega SmartThings! -'''Click 'Done' to finish setup.'''=Klõpsake valikut Valmis, et seadistamine lõpule viia. -'''SmartThings Connection'''=Teenuse SmartThings ühendus -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Seadmed lisatakse automaatselt teie kontolt LIFX. Seadmete lisamiseks või kustutamiseks kasutage ametlikku kaupleja LIFX rakendust. -'''Set for specific mode(s)'''=Valige konkreetne režiim / konkreetsed režiimid -'''Assign a name'''=Määrake nimi -'''Tap to set'''=Toksake, et määrata -'''Phone'''=Telefoninumber -'''Which?'''=Milline? -'''Add a name'''=Lisa nimi -'''Tap to choose'''=Toksake, et valida -'''Choose an icon'''=Vali ikoon -'''Next page'''=Järgmine leht -'''Text'''=Tekst -'''Number'''=Number diff --git a/smartapps/smartthings/lifx-connect.src/i18n/fi-FI.properties b/smartapps/smartthings/lifx-connect.src/i18n/fi-FI.properties deleted file mode 100644 index c42bd597dcc..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/fi-FI.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Mahdollistaa LIFX-älylamppujen käytön SmartThingsin kanssa. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Anna LIFX-tunnistetiedot -'''Connect to LIFX'''=Muodosta LIFX-yhteys -'''Tap here to connect your LIFX account'''=Napauta tätä, jos haluat muodostaa yhteyden LIFX-tiliisi -'''Connect to LIFX'''=Muodosta LIFX-yhteys -'''Select your location'''=Valitse sijaintisi -'''Select location ({{count}} found)'''=Valitse sijainti ({{count}} löydetty) -'''Your LIFX Account is now connected to SmartThings!'''=LIFX-tilisi on nyt yhdistetty SmartThingsiin! -'''Click 'Done' to finish setup.'''=Viimeistele asennus napsauttamalla Done (Valmis). -'''The connection could not be established!'''=Yhteyden muodostaminen epäonnistui! -'''Click 'Done' to return to the menu.'''=Palaa valikkoon napsauttamalla Done (Valmis). -'''Your LIFX Account is already connected to SmartThings!'''=LIFX-tilisi on jo yhdistetty SmartThingsiin! -'''Click 'Done' to finish setup.'''=Viimeistele asennus napsauttamalla Done (Valmis). -'''SmartThings Connection'''=SmartThings-yhteys -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Laitteet lisätään automaattisesti yrityksen LIFX tililtä. Jos haluat lisätä tai poistaa laitteita, käytä yrityksen LIFX virallista sovellusta. -'''Set for specific mode(s)'''=Aseta tiettyjä tiloja varten -'''Assign a name'''=Määritä nimi -'''Tap to set'''=Aseta napauttamalla tätä -'''Phone'''=Puhelinnumero -'''Which?'''=Mikä? -'''Add a name'''=Lisää nimi -'''Tap to choose'''=Valitse napauttamalla -'''Choose an icon'''=Valitse kuvake -'''Next page'''=Seuraava sivu -'''Text'''=Teksti -'''Number'''=Numero diff --git a/smartapps/smartthings/lifx-connect.src/i18n/fr-CA.properties b/smartapps/smartthings/lifx-connect.src/i18n/fr-CA.properties deleted file mode 100644 index 109a34b8c78..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/fr-CA.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Vous permet d'utiliser des ampoules intelligentes LIFX avec SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Appuyez pour saisir les informations d'identification LIFX -'''Connect to LIFX'''=Connexion à LIFX -'''Tap here to connect your LIFX account'''=Appuyez ici pour connecter votre compte LIFX -'''Connect to LIFX'''=Connexion à LIFX -'''Select your location'''=Sélection de votre zone géographique -'''Select location ({{count}} found)'''=Sélection d'une zone géographique ({{count}} trouvée(s)) -'''Your LIFX Account is now connected to SmartThings!'''=Votre compte LIFX est maintenant connecté à SmartThings ! -'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration. -'''The connection could not be established!'''=La connexion n'a pas pu être établie ! -'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu. -'''Your LIFX Account is already connected to SmartThings!'''=Votre compte LIFX est déjà connecté à SmartThings ! -'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration. -'''SmartThings Connection'''=Connexion SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Les appareils seront ajoutés automatiquement à partir de votre compte LIFX. Pour ajouter ou supprimer des appareils, veuillez utiliser l’application LIFX officielle. -'''Set for specific mode(s)'''=Régler pour un ou des mode(s) spécifique(s) -'''Assign a name'''=Assigner un nom -'''Tap to set'''=Toucher pour régler -'''Phone'''=Numéro de téléphone -'''Which?'''=Lequel? -'''Add a name'''=Ajouter un nom -'''Tap to choose'''=Toucher pour choisir -'''Choose an icon'''=Choisir une icône -'''Next page'''=Page suivante -'''Text'''=Texte -'''Number'''=Numéro diff --git a/smartapps/smartthings/lifx-connect.src/i18n/fr-FR.properties b/smartapps/smartthings/lifx-connect.src/i18n/fr-FR.properties deleted file mode 100644 index 059ca07034c..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/fr-FR.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Vous permet d'utiliser des ampoules intelligentes LIFX avec SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Appuyez pour saisir les informations d'identification LIFX -'''Connect to LIFX'''=Connexion à LIFX -'''Tap here to connect your LIFX account'''=Appuyez ici pour connecter votre compte LIFX -'''Connect to LIFX'''=Connexion à LIFX -'''Select your location'''=Sélection de votre zone géographique -'''Select location ({{count}} found)'''=Sélection d'une zone géographique ({{count}} trouvée(s)) -'''Your LIFX Account is now connected to SmartThings!'''=Votre compte LIFX est maintenant connecté à SmartThings ! -'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration. -'''The connection could not be established!'''=La connexion n'a pas pu être établie ! -'''Click 'Done' to return to the menu.'''=Cliquez sur Done (Terminé) pour revenir au menu. -'''Your LIFX Account is already connected to SmartThings!'''=Votre compte LIFX est déjà connecté à SmartThings ! -'''Click 'Done' to finish setup.'''=Cliquez sur Done (Terminé) pour terminer la configuration. -'''SmartThings Connection'''=Connexion SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Les appareils seront ajoutés automatiquement à partir de votre compte LIFX. Pour ajouter ou supprimer des appareils, utilisez l'application LIFX officielle. -'''Set for specific mode(s)'''=Réglage pour mode(s) spécifique(s) -'''Assign a name'''=Attribuer un nom -'''Tap to set'''=Appuyez pour définir -'''Phone'''=Numéro de téléphone -'''Which?'''=Lequel ? -'''Add a name'''=Ajouter un nom -'''Tap to choose'''=Appuyer pour choisir -'''Choose an icon'''=Choisir une icône -'''Next page'''=Page suivante -'''Text'''=Texte -'''Number'''=Nombre diff --git a/smartapps/smartthings/lifx-connect.src/i18n/hr-HR.properties b/smartapps/smartthings/lifx-connect.src/i18n/hr-HR.properties deleted file mode 100644 index 6624cfdf7bf..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/hr-HR.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Dopušta vam da upotrebljavate pametne žarulje LIFX s uslugom SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Dodirnite za unos podataka za prijavu za LIFX -'''Connect to LIFX'''=Povezivanje na LIFX -'''Tap here to connect your LIFX account'''=Dodirnite ovdje da biste povezali svoj račun za LIFX -'''Connect to LIFX'''=Povezivanje na LIFX -'''Select your location'''=Odaberite lokaciju -'''Select location ({{count}} found)'''=Odaberite lokaciju (pronađeno: {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Račun za LIFX sada je povezan s uslugom SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite „Done” (Gotovo) da biste dovršili postavljanje. -'''The connection could not be established!'''=Veza se nije uspostavila! -'''Click 'Done' to return to the menu.'''=Kliknite „Done” (Gotovo) za vraćanje na izbornik. -'''Your LIFX Account is already connected to SmartThings!'''=Račun za LIFX već je povezan s uslugom SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite „Done” (Gotovo) da biste dovršili postavljanje. -'''SmartThings Connection'''=Veza za SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Uređaji će se automatski dodati s računa tvrtke LIFX. Da biste dodali ili izbrisali uređaje, upotrebljavajte službenu aplikaciju tvrtke LIFX. -'''Set for specific mode(s)'''=Postavi za određeni način rada (ili više njih) -'''Assign a name'''=Dodijeli naziv -'''Tap to set'''=Dodirnite za postavljanje -'''Phone'''=Telefonski broj -'''Which?'''=Koji? -'''Add a name'''=Dodajte naziv -'''Tap to choose'''=Dodirnite za odabir -'''Choose an icon'''=Odaberite ikonu -'''Next page'''=Sljedeća stranica -'''Text'''=Tekst -'''Number'''=Broj diff --git a/smartapps/smartthings/lifx-connect.src/i18n/hu-HU.properties b/smartapps/smartthings/lifx-connect.src/i18n/hu-HU.properties deleted file mode 100644 index 5e69b52b77b..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/hu-HU.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Lehetővé teszi a LIFX okoségők használatát a SmartThings rendszerrel. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Érintse meg a LIFX-hitelesítőadatok megadásához -'''Connect to LIFX'''=Csatlakozás a LIFX-hez -'''Tap here to connect your LIFX account'''=Érintse meg a LIFX-fiókjához való csatlakozáshoz -'''Connect to LIFX'''=Csatlakozás a LIFX-hez -'''Select your location'''=Hely kiválasztása -'''Select location ({{count}} found)'''=Hely kiválasztása ({{count}} találat) -'''Your LIFX Account is now connected to SmartThings!'''=Csatlakoztatta LIFX-fiókját a SmartThings rendszerhez! -'''Click 'Done' to finish setup.'''=A telepítés befejezéséhez kattintson a „Done” (Kész) gombra. -'''The connection could not be established!'''=Nem sikerült kapcsolatot létesíteni! -'''Click 'Done' to return to the menu.'''=A menühöz való visszatéréshez kattintson a „Done” (Kész) gombra. -'''Your LIFX Account is already connected to SmartThings!'''=LIFX-fiókja már csatlakozott a SmartThings rendszerhez! -'''Click 'Done' to finish setup.'''=A telepítés befejezéséhez kattintson a „Done” (Kész) gombra. -'''SmartThings Connection'''=SmartThings csatlakoztatása -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=A rendszer automatikusan hozzá fogja adni az eszközöket a(z) LIFX-fiókból. Az eszközök hozzáadásához vagy törléséhez használja a hivatalos LIFX alkalmazást. -'''Set for specific mode(s)'''=Beállítás adott mód(ok)hoz -'''Assign a name'''=Név hozzárendelése -'''Tap to set'''=Érintse meg a beállításhoz -'''Phone'''=Telefonszám -'''Which?'''=Melyik? -'''Add a name'''=Név hozzáadása -'''Tap to choose'''=Érintse meg a kiválasztáshoz -'''Choose an icon'''=Ikon kiválasztása -'''Next page'''=Következő oldal -'''Text'''=Szöveg -'''Number'''=Szám diff --git a/smartapps/smartthings/lifx-connect.src/i18n/it-IT.properties b/smartapps/smartthings/lifx-connect.src/i18n/it-IT.properties deleted file mode 100644 index b7e889d641d..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/it-IT.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Vi consente di utilizzare le lampadine intelligenti LIFX con SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Toccate per inserire le credenziali LIFX -'''Connect to LIFX'''=Connetti a LIFX -'''Tap here to connect your LIFX account'''=Toccate qui per connettere l'account LIFX -'''Connect to LIFX'''=Connetti a LIFX -'''Select your location'''=Selezionate la posizione -'''Select location ({{count}} found)'''=Selezionate la posizione ({{count}} trovate) -'''Your LIFX Account is now connected to SmartThings!'''=L'account LIFX è adesso connesso a SmartThings. -'''Click 'Done' to finish setup.'''=Fate clic su “Done” (Fatto) per terminare la configurazione. -'''The connection could not be established!'''=Non è stato possibile stabilire la connessione. -'''Click 'Done' to return to the menu.'''=Fate clic su “Done” (Fatto) per tornare al menu. -'''Your LIFX Account is already connected to SmartThings!'''=L'account LIFX è già connesso a SmartThings. -'''Click 'Done' to finish setup.'''=Fate clic su “Done” (Fatto) per terminare la configurazione. -'''SmartThings Connection'''=Connessione a SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=I dispositivi verranno aggiunti automaticamente dal vostro account LIFX. Per aggiungere o eliminare dispositivi, usate l’applicazione ufficiale LIFX. -'''Set for specific mode(s)'''=Imposta per modalità specifiche -'''Assign a name'''=Assegna nome -'''Tap to set'''=Toccate per impostare -'''Phone'''=Numero di telefono -'''Which?'''=Quale? -'''Add a name'''=Aggiungete un nome -'''Tap to choose'''=Toccate per scegliere -'''Choose an icon'''=Scegliete un’icona -'''Next page'''=Pagina successiva -'''Text'''=Testo -'''Number'''=Numero diff --git a/smartapps/smartthings/lifx-connect.src/i18n/ko-KR.properties b/smartapps/smartthings/lifx-connect.src/i18n/ko-KR.properties deleted file mode 100644 index 71e16d79156..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/ko-KR.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=LIFX 스마트 전구를 SmartThings에서 사용할 수 있습니다. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=LIFX 로그인 정보를 입력하려면 누르세요 -'''Connect to LIFX'''=LIFX 연결 -'''Tap here to connect your LIFX account'''=LIFX 계정을 연결하려면 여기를 누르세요 -'''Connect to LIFX'''=LIFX 연결 -'''Select your location'''=위치 선택 -'''Select location ({{count}} found)'''=위치 선택 ({{count}}개 찾음) -'''Your LIFX Account is now connected to SmartThings!'''=LIFX 계정이 SmartThings에 연결되었습니다! -'''Click 'Done' to finish setup.'''=설정을 완료하려면 [완료]를 클릭하세요. -'''The connection could not be established!'''=연결을 실행할 수 없습니다! -'''Click 'Done' to return to the menu.'''=메뉴로 돌아가려면 [완료]를 클릭하세요. -'''Your LIFX Account is already connected to SmartThings!'''=LIFX 계정이 SmartThings에 연결되어 있습니다! -'''Click 'Done' to finish setup.'''=설정을 완료하려면 [완료]를 클릭하세요. -'''SmartThings Connection'''=SmartThings 연결 -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=디바이스가 LIFX 계정에서 자동으로 추가됩니다. 디바이스를 추가하거나 삭제하려면 LIFX 공식 앱을 사용하세요. -'''Set for specific mode(s)'''=특정 모드 설정 -'''Assign a name'''=이름 지정 -'''Tap to set'''=설정하려면 누르세요 -'''Phone'''=전화번호 -'''Which?'''=사용할 장치는? -'''Add a name'''=이름 추가 -'''Tap to choose'''=눌러서 선택 -'''Choose an icon'''=아이콘 선택 -'''Next page'''=다음 페이지 -'''Text'''=텍스트 -'''Number'''=번호 diff --git a/smartapps/smartthings/lifx-connect.src/i18n/nl-NL.properties b/smartapps/smartthings/lifx-connect.src/i18n/nl-NL.properties deleted file mode 100644 index 63864bf4b58..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/nl-NL.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Hiermee kunt u slimme lampen van LIFX gebruiken met SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Tik om LIFX-inloggegevens in te voeren -'''Connect to LIFX'''=Verbinden met LIFX -'''Tap here to connect your LIFX account'''=Tik hier om verbinding te maken met uw LIFX-account -'''Connect to LIFX'''=Verbinden met LIFX -'''Select your location'''=Selecteer uw locatie -'''Select location ({{count}} found)'''=Selecteer locatie ({{count}} gevonden) -'''Your LIFX Account is now connected to SmartThings!'''=Uw LIFX-account is nu verbonden met SmartThings. -'''Click 'Done' to finish setup.'''=Klik op Done (Gereed) om het instellen te voltooien. -'''The connection could not be established!'''=Er kan geen verbinding worden gemaakt. -'''Click 'Done' to return to the menu.'''=Klik op Done (Gereed) om terug te gaan naar het menu. -'''Your LIFX Account is already connected to SmartThings!'''=Uw LIFX-account is al verbonden met SmartThings. -'''Click 'Done' to finish setup.'''=Klik op Done (Gereed) om het instellen te voltooien. -'''SmartThings Connection'''=SmartThings-verbinding -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Apparaten worden automatisch toegevoegd uit uw LIFX-account. Gebruik de officiële LIFX-app om apparaten toe te voegen of te verwijderen. -'''Set for specific mode(s)'''=Instellen voor specifieke stand(en) -'''Assign a name'''=Een naam toewijzen -'''Tap to set'''=Tik om in te stellen -'''Phone'''=Telefoonnummer -'''Which?'''=Welke? -'''Add a name'''=Een naam toevoegen -'''Tap to choose'''=Tik om te kiezen -'''Choose an icon'''=Een pictogram kiezen -'''Next page'''=Volgende pagina -'''Text'''=Tekst -'''Number'''=Nummer diff --git a/smartapps/smartthings/lifx-connect.src/i18n/no-NO.properties b/smartapps/smartthings/lifx-connect.src/i18n/no-NO.properties deleted file mode 100644 index 162524801b1..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/no-NO.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Gjør at du kan bruke LIFX-smartlyspærer med SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Trykk for å angi LIFX-informasjon -'''Connect to LIFX'''=Koble til LIFX -'''Tap here to connect your LIFX account'''=Trykk her for å koble til LIFX-kontoen din -'''Connect to LIFX'''=Koble til LIFX -'''Select your location'''=Velg plasseringen din -'''Select location ({{count}} found)'''=Velg plassering (fant {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=LIFX-kontoen din er nå koblet til SmartThings! -'''Click 'Done' to finish setup.'''=Klikk på Done (Ferdig) for å fullføre oppsettet. -'''The connection could not be established!'''=Kunne ikke opprette tilkoblingen! -'''Click 'Done' to return to the menu.'''=Klikk på Done (Ferdig) for å gå tilbake til menyen. -'''Your LIFX Account is already connected to SmartThings!'''=LIFX-kontoen din er allerede koblet til SmartThings! -'''Click 'Done' to finish setup.'''=Klikk på Done (Ferdig) for å fullføre oppsettet. -'''SmartThings Connection'''=SmartThings-tilkobling -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Enheter blir lagt til automatisk fra LIFX-kontoen. For å legge til eller slette enheter bruker du den offisielle LIFX-appen. -'''Set for specific mode(s)'''=Angi for bestemte moduser -'''Assign a name'''=Tildel et navn -'''Tap to set'''=Trykk for å angi -'''Phone'''=Telefonnummer -'''Which?'''=Hvilken? -'''Add a name'''=Legg til et navn -'''Tap to choose'''=Trykk for å velge -'''Choose an icon'''=Velg et ikon -'''Next page'''=Neste side -'''Text'''=Tekst -'''Number'''=Nummer diff --git a/smartapps/smartthings/lifx-connect.src/i18n/pl-PL.properties b/smartapps/smartthings/lifx-connect.src/i18n/pl-PL.properties deleted file mode 100644 index 60bc947544e..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/pl-PL.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Umożliwia użycie inteligentnych żarówek LIFX ze SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Dotknij, aby wprowadzić poświadczenia LIFX -'''Connect to LIFX'''=Połącz z LIFX -'''Tap here to connect your LIFX account'''=Dotknij tutaj, aby połączyć z kontem LIFX -'''Connect to LIFX'''=Połącz z LIFX -'''Select your location'''=Wybierz lokalizację -'''Select location ({{count}} found)'''=Wybierz lokalizację (znaleziono {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Konto LIFX jest teraz połączone ze SmartThings. -'''Click 'Done' to finish setup.'''=Kliknij opcję „Done” (Gotowe), aby ukończyć instalację. -'''The connection could not be established!'''=Nie można ustanowić połączenia. -'''Click 'Done' to return to the menu.'''=Kliknij opcję „Done” (Gotowe), aby powrócić do menu. -'''Your LIFX Account is already connected to SmartThings!'''=Konto LIFX jest już połączone ze SmartThings. -'''Click 'Done' to finish setup.'''=Kliknij opcję „Done” (Gotowe), aby ukończyć instalację. -'''SmartThings Connection'''=Połączenie SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Urządzenia zostaną dodane automatycznie z Twojego konta LIFX. Aby dodać lub usunąć urządzenia, użyj oficjalnej aplikacji LIFX. -'''Set for specific mode(s)'''=Ustaw dla określonych trybów -'''Assign a name'''=Przypisz nazwę -'''Tap to set'''=Dotknij, aby ustawić -'''Phone'''=Numer telefonu -'''Which?'''=Który? -'''Add a name'''=Dodaj nazwę -'''Tap to choose'''=Dotknij, aby wybrać -'''Choose an icon'''=Wybór ikony -'''Next page'''=Następna strona -'''Text'''=Tekst -'''Number'''=Numer diff --git a/smartapps/smartthings/lifx-connect.src/i18n/pt-BR.properties b/smartapps/smartthings/lifx-connect.src/i18n/pt-BR.properties deleted file mode 100644 index c6515eb28a5..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/pt-BR.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Permite o uso de lâmpadas inteligentes LIFX com o SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Tocar para inserir as credenciais do LIFX -'''Connect to LIFX'''=Conectar ao LIFX -'''Tap here to connect your LIFX account'''=Tocar aqui para conectar sua conta LIFX -'''Connect to LIFX'''=Conectar ao LIFX -'''Select your location'''=Selecionar sua localização -'''Select location ({{count}} found)'''=Selecionar a localização ({{count}} encontrado) -'''Your LIFX Account is now connected to SmartThings!'''=Agora sua conta LIFX está conectada ao SmartThings! -'''Click 'Done' to finish setup.'''=Clique em 'Done' (Concluído) para concluir a configuração. -'''The connection could not be established!'''=Não foi possível estabelecer a conexão! -'''Click 'Done' to return to the menu.'''=Clique em 'Done' (Concluído) para retornar ao menu. -'''Your LIFX Account is already connected to SmartThings!'''=Sua conta LIFX já está conectada ao SmartThings! -'''Click 'Done' to finish setup.'''=Clique em 'Done' (Concluído) para concluir a configuração. -'''SmartThings Connection'''=Conexão com o SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Os aparelhos serão adicionados automaticamente da sua conta LIFX. Para adicionar ou excluir aparelhos, use o aplicativo oficial LIFX. -'''Set for specific mode(s)'''=Definir para modo(s) específico(s) -'''Assign a name'''=Atribuir um nome -'''Tap to set'''=Toque para definir -'''Phone'''=Número de telefone -'''Which?'''=Qual? -'''Add a name'''=Adicione um nome -'''Tap to choose'''=Toque para escolher -'''Choose an icon'''=Escolha um ícone -'''Next page'''=Próxima página -'''Text'''=Texto -'''Number'''=Número diff --git a/smartapps/smartthings/lifx-connect.src/i18n/pt-PT.properties b/smartapps/smartthings/lifx-connect.src/i18n/pt-PT.properties deleted file mode 100644 index 7f0ac4252dd..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/pt-PT.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Permite a utilização de lâmpadas inteligentes LIFX com o SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Toque para introduzir as credenciais da LIFX -'''Connect to LIFX'''=Ligar à LIFX -'''Tap here to connect your LIFX account'''=Toque aqui para ligar a sua conta LIFX -'''Connect to LIFX'''=Ligar à LIFX -'''Select your location'''=Seleccionar a sua localização -'''Select location ({{count}} found)'''=Seleccionar a localização ({{count}} encontrado) -'''Your LIFX Account is now connected to SmartThings!'''=Agora, a sua Conta LIFX está ligada ao SmartThings! -'''Click 'Done' to finish setup.'''=Clique em "Done" (Concluir) para terminar a configuração. -'''The connection could not be established!'''=Não foi possível estabelecer a ligação! -'''Click 'Done' to return to the menu.'''=Clique em "Done" (Concluir) para regressar ao menu. -'''Your LIFX Account is already connected to SmartThings!'''=A sua conta LIFX já está ligada ao SmartThings! -'''Click 'Done' to finish setup.'''=Clique em "Done" (Concluir) para terminar a configuração. -'''SmartThings Connection'''=Ligação do SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Os dispositivos serão adicionados automaticamente a partir da sua conta LIFX. Para adicionar ou eliminar dispositivos, utilize a aplicação LIFX oficial. -'''Set for specific mode(s)'''=Definir para modo(s) específico(s) -'''Assign a name'''=Atribuir um nome -'''Tap to set'''=Tocar para definir -'''Phone'''=Número de Telefone -'''Which?'''=Qual? -'''Add a name'''=Adicionar um nome -'''Tap to choose'''=Tocar para escolher -'''Choose an icon'''=Escolher um ícone -'''Next page'''=Página seguinte -'''Text'''=Texto -'''Number'''=Número diff --git a/smartapps/smartthings/lifx-connect.src/i18n/ro-RO.properties b/smartapps/smartthings/lifx-connect.src/i18n/ro-RO.properties deleted file mode 100644 index 0b8728ad420..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/ro-RO.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Permite utilizarea becurilor inteligente LIFX cu SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Atingeți pentru a introduce acreditările LIFX -'''Connect to LIFX'''=Conectare la LIFX -'''Tap here to connect your LIFX account'''=Atingeți aici pentru a vă conecta la contul LIFX -'''Connect to LIFX'''=Conectare la LIFX -'''Select your location'''=Selectați locația dvs. -'''Select location ({{count}} found)'''=Selectare locație ({{count}} găsite) -'''Your LIFX Account is now connected to SmartThings!'''=Contul dvs. LIFX este acum conectat la SmartThings! -'''Click 'Done' to finish setup.'''=Faceți clic pe „Done” (Efectuat) pentru a finaliza configurarea. -'''The connection could not be established!'''=Nu a putut fi stabilită conexiunea! -'''Click 'Done' to return to the menu.'''=Faceți clic pe „Done” (Efectuat) pentru a reveni la meniu. -'''Your LIFX Account is already connected to SmartThings!'''=Contul dvs. LIFX este deja conectat la SmartThings! -'''Click 'Done' to finish setup.'''=Faceți clic pe „Done” (Efectuat) pentru a finaliza configurarea. -'''SmartThings Connection'''=Conexiune SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Dispozitivele vor fi adăugate automat din contul LIFX. Pentru a adăuga sau a șterge dispozitive, utilizați aplicația oficială de la LIFX. -'''Set for specific mode(s)'''=Setați pentru anumite moduri -'''Assign a name'''=Atribuiți un nume -'''Tap to set'''=Atingeți pentru a seta -'''Phone'''=Număr de telefon -'''Which?'''=Care? -'''Add a name'''=Adăugați un nume -'''Tap to choose'''=Atingeți pentru a selecta -'''Choose an icon'''=Selectați o pictogramă -'''Next page'''=Pagina următoare -'''Text'''=Text -'''Number'''=Număr diff --git a/smartapps/smartthings/lifx-connect.src/i18n/ru-RU.properties b/smartapps/smartthings/lifx-connect.src/i18n/ru-RU.properties deleted file mode 100644 index bcca4e43bdd..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/ru-RU.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Позволяет использовать умные электролампы LIFX со SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Коснитесь, чтобы ввести учетные данные LIFX -'''Connect to LIFX'''=Подключиться к LIFX -'''Tap here to connect your LIFX account'''=Коснитесь здесь, чтобы подключить свою учетную запись LIFX -'''Connect to LIFX'''=Подключиться к LIFX -'''Select your location'''=Выберите свое месторасположение -'''Select location ({{count}} found)'''=Выбор местоположения (найдено {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Теперь ваша учетная запись LIFX подключена к SmartThings! -'''Click 'Done' to finish setup.'''=Для завершения настройки нажмите «Готово». -'''The connection could not be established!'''=Не удалось установить соединение! -'''Click 'Done' to return to the menu.'''=Чтобы вернуться в меню, нажмите «Готово». -'''Your LIFX Account is already connected to SmartThings!'''=Ваша учетная запись LIFX уже подключена к SmartThings! -'''Click 'Done' to finish setup.'''=Для завершения настройки нажмите «Готово». -'''SmartThings Connection'''=Подключение SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Устройства будут автоматически добавлены из вашей учетной записи LIFX. Для добавления и удаления устройств используйте официальное приложение LIFX -'''Set for specific mode(s)'''=Установить для определенного режима (режимов) -'''Assign a name'''=Назначить название -'''Tap to set'''=Коснитесь, чтобы установить -'''Phone'''=Номер телефона -'''Which?'''=Который? -'''Add a name'''=Добавить название -'''Tap to choose'''=Коснитесь, чтобы выбрать -'''Choose an icon'''=Выбрать значок -'''Next page'''=Следующая страница -'''Text'''=Текст -'''Number'''=Номер diff --git a/smartapps/smartthings/lifx-connect.src/i18n/sk-SK.properties b/smartapps/smartthings/lifx-connect.src/i18n/sk-SK.properties deleted file mode 100644 index 9d28e45b83e..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/sk-SK.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Umožňuje používať inteligentné žiarovky LIFX so systémom SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Ťuknutím zadajte poverenia pre LIFX -'''Connect to LIFX'''=Pripojenie k zariadeniu LIFX -'''Tap here to connect your LIFX account'''=Ťuknutím sem sa môžete pripojiť ku kontu LIFX -'''Connect to LIFX'''=Pripojenie k zariadeniu LIFX -'''Select your location'''=Vyberte umiestnenie -'''Select location ({{count}} found)'''=Vyberte umiestnenie (nájdené: {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Vaše konto LIFX je teraz prepojené so systémom SmartThings. -'''Click 'Done' to finish setup.'''=Kliknutím na tlačidlo Done (Hotovo) dokončite inštaláciu. -'''The connection could not be established!'''=Nepodarilo sa nadviazať spojenie. -'''Click 'Done' to return to the menu.'''=Kliknutím na tlačidlo Done (Hotovo) sa vráťte do menu. -'''Your LIFX Account is already connected to SmartThings!'''=Vaše konto LIFX je už prepojené so systémom SmartThings. -'''Click 'Done' to finish setup.'''=Kliknutím na tlačidlo Done (Hotovo) dokončite inštaláciu. -'''SmartThings Connection'''=Pripojenie k zariadeniu SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Zariadenia sa automaticky pridajú z vášho konta LIFX. Ak chcete pridať alebo odstrániť zariadenia, použite oficiálnu aplikáciu LIFX. -'''Set for specific mode(s)'''=Nastaviť pre konkrétne režimy -'''Assign a name'''=Priradiť názov -'''Tap to set'''=Ťuknutím môžete nastaviť -'''Phone'''=Telefónne číslo -'''Which?'''=Ktorý? -'''Add a name'''=Pridajte názov -'''Tap to choose'''=Ťuknutím vyberte -'''Choose an icon'''=Vyberte ikonu -'''Next page'''=Nasledujúca strana -'''Text'''=Text -'''Number'''=Číslo diff --git a/smartapps/smartthings/lifx-connect.src/i18n/sl-SI.properties b/smartapps/smartthings/lifx-connect.src/i18n/sl-SI.properties deleted file mode 100644 index 3af6912c076..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/sl-SI.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Omogoča uporabo pametnih žarnic LIFX s storitvijo SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Pritisnite za vnos poverilnic LIFX -'''Connect to LIFX'''=Povezava z LIFX -'''Tap here to connect your LIFX account'''=Pritisnite tukaj, da povežete račun LIFX -'''Connect to LIFX'''=Povezava z LIFX -'''Select your location'''=Izberite svojo lokacijo -'''Select location ({{count}} found)'''=Izberite lokacijo (št. najdenih: {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Vaš račun LIFX je zdaj povezan s storitvijo SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite »Done« (Končano), da zaključite nastavitev. -'''The connection could not be established!'''=Povezave ni bilo mogoče vzpostaviti! -'''Click 'Done' to return to the menu.'''=Kliknite »Done« (Končano), da se vrnete v meni. -'''Your LIFX Account is already connected to SmartThings!'''=Račun LIFX je že povezan s storitvijo SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite »Done« (Končano), da zaključite nastavitev. -'''SmartThings Connection'''=Povezava SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Naprave bodo samodejno dodane iz vašega računa LIFX. Če želite dodati ali izbrisati naprave, uporabite uradno aplikacijo ponudnika LIFX. -'''Set for specific mode(s)'''=Nastavi za določene načine -'''Assign a name'''=Določi ime -'''Tap to set'''=Pritisnite za nastavitev -'''Phone'''=Telefonska številka -'''Which?'''=Kateri? -'''Add a name'''=Dodajte ime -'''Tap to choose'''=Pritisnite za izbiro -'''Choose an icon'''=Izberite ikono -'''Next page'''=Naslednja stran -'''Text'''=Besedilo -'''Number'''=Številka diff --git a/smartapps/smartthings/lifx-connect.src/i18n/sq-AL.properties b/smartapps/smartthings/lifx-connect.src/i18n/sq-AL.properties deleted file mode 100644 index 14fe58fe11b..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/sq-AL.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Të lejon të përdorësh llamba inteligjente LIFX me SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Trokit për të futur kredencialet LIFX -'''Connect to LIFX'''=Lidhu me LIFX -'''Tap here to connect your LIFX account'''=Trokit këtu për të lidhur llogarinë LIFX -'''Connect to LIFX'''=Lidhu me LIFX -'''Select your location'''=Përzgjidh vendndodhjen tënde -'''Select location ({{count}} found)'''=Përzgjidh vendndodhjen (u gjet {{count}}) -'''Your LIFX Account is now connected to SmartThings!'''=Llogaria jote LIFX tani është lidhur me SmartThings! -'''Click 'Done' to finish setup.'''=Kliko mbi ‘Done’ (U krye) për ta mbaruar konfigurimin. -'''The connection could not be established!'''=Lidhja nuk u vendos dot! -'''Click 'Done' to return to the menu.'''=Kliko mbi ‘Done’ (U krye) për t’u kthyer në meny. -'''Your LIFX Account is already connected to SmartThings!'''=Llogaria jote LIFX tashmë është lidhur me SmartThings! -'''Click 'Done' to finish setup.'''=Kliko mbi ‘Done’ (U krye) për ta mbaruar konfigurimin. -'''SmartThings Connection'''=Lidhja SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Pajisjet do të shtohen automatikisht nga llogaria jote LIFX. Për të shtuar ose hequr pajisje, përdor app-in zyrtar LIFX. -'''Set for specific mode(s)'''=Cilëso për regjim(e) specifik(e) -'''Assign a name'''=Vëri një emër -'''Tap to set'''=Trokit për ta cilësuar -'''Phone'''=Numri i telefonit -'''Which?'''=Çfarë? -'''Add a name'''=Shto një emër -'''Tap to choose'''=Trokit për të zgjedhur -'''Choose an icon'''=Zgjidh një ikonë -'''Next page'''=Faqja pasuese -'''Text'''=Tekst -'''Number'''=Numër diff --git a/smartapps/smartthings/lifx-connect.src/i18n/sr-RS.properties b/smartapps/smartthings/lifx-connect.src/i18n/sr-RS.properties deleted file mode 100644 index 1b9293d5c0e..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/sr-RS.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Dozvoljava vam da koristite LIFX pametne sijalice sa aplikacijom SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Kucnite za unos LIFX akreditiva -'''Connect to LIFX'''=Povežite se na LIFX -'''Tap here to connect your LIFX account'''=Kucnite ovde da biste se povezali na svoj LIFX nalog -'''Connect to LIFX'''=Povežite se na LIFX -'''Select your location'''=Izaberite lokaciju na kojoj se nalazite -'''Select location ({{count}} found)'''=Izaberite lokaciju ({{count}} pronađeno) -'''Your LIFX Account is now connected to SmartThings!'''=Vaš LIFX nalog je sada povezan na SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite na „Done” (Gotovo) za kraj konfiguracije. -'''The connection could not be established!'''=Veza nije uspostavljena! -'''Click 'Done' to return to the menu.'''=Kliknite na „Done” (Gotovo) da biste se vratili na meni. -'''Your LIFX Account is already connected to SmartThings!'''=Vaš LIFX nalog je već povezan na SmartThings! -'''Click 'Done' to finish setup.'''=Kliknite na „Done” (Gotovo) za kraj konfiguracije. -'''SmartThings Connection'''=SmartThings veza -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Uređaji će se automatski dodati sa LIFX naloga. Da biste dodali ili izbrisali uređaje, koristite zvaničnu LIFX aplikaciju. -'''Set for specific mode(s)'''=Podesi za određene režime -'''Assign a name'''=Dodeli ime -'''Tap to set'''=Kucnite da biste podesili -'''Phone'''=Broj telefona -'''Which?'''=Koje? -'''Add a name'''=Dodajte ime -'''Tap to choose'''=Kucnite da biste izabrali -'''Choose an icon'''=Izaberite ikonu -'''Next page'''=Sledeća strana -'''Text'''=Tekst -'''Number'''=Broj diff --git a/smartapps/smartthings/lifx-connect.src/i18n/sv-SE.properties b/smartapps/smartthings/lifx-connect.src/i18n/sv-SE.properties deleted file mode 100644 index 9855a9176ff..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/sv-SE.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=Gör att du kan använda de smarta LIFX-lamporna med SmartThings. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=Tryck för att ange LIFX-inloggningsuppgifter -'''Connect to LIFX'''=Anslut till LIFX -'''Tap here to connect your LIFX account'''=Tryck här för att avsluta ditt LIFX-konto -'''Connect to LIFX'''=Anslut till LIFX -'''Select your location'''=Välj din plats -'''Select location ({{count}} found)'''=Välj plats ({{count}} hittades) -'''Your LIFX Account is now connected to SmartThings!'''=Ditt LIFX-konto är nu anslutet till SmartThings! -'''Click 'Done' to finish setup.'''=Klicka på Done (Klart) för att slutföra konfigurationen. -'''The connection could not be established!'''=Det gick inte att upprätta anslutningen! -'''Click 'Done' to return to the menu.'''=Klicka på Done (Klart) för att återgå till menyn. -'''Your LIFX Account is already connected to SmartThings!'''=Ditt LIFX-konto är redan anslutet till SmartThings! -'''Click 'Done' to finish setup.'''=Klicka på Done (Klart) för att slutföra konfigurationen. -'''SmartThings Connection'''=SmartThings-anslutning -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Enheter läggs till automatiskt från ditt LIFX-konto. Om du vill lägga till ett ta bort enheter ska du använda den officiella LIFX-appen. -'''Set for specific mode(s)'''=Ställ in för vissa lägen -'''Assign a name'''=Ge ett namn -'''Tap to set'''=Tryck för att ställa in -'''Phone'''=Telefonnummer -'''Which?'''=Vilket? -'''Add a name'''=Lägg till ett namn -'''Tap to choose'''=Tryck för att välja -'''Choose an icon'''=Välj en ikon -'''Next page'''=Nästa sida -'''Text'''=Text -'''Number'''=Tal diff --git a/smartapps/smartthings/lifx-connect.src/i18n/th-TH.properties b/smartapps/smartthings/lifx-connect.src/i18n/th-TH.properties deleted file mode 100644 index bafb6178fc0..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/th-TH.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=ทำให้คุณสามารถใช้หลอดไฟอัจฉริยะ LIFX กับ SmartThings ได้ -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=แตะเพื่อใส่ข้อมูลยืนยันตัวตน LIFX -'''Connect to LIFX'''=เชื่อมต่อกับ LIFX -'''Tap here to connect your LIFX account'''=แตะที่นี่เพื่อเชื่อมต่อบัญชีผู้ใช้ LIFX ของคุณ -'''Connect to LIFX'''=เชื่อมต่อกับ LIFX -'''Select your location'''=เลือกตำแหน่งของคุณ -'''Select location ({{count}} found)'''=เลือกตำแหน่ง ({{count}} found) -'''Your LIFX Account is now connected to SmartThings!'''=ตอนนี้บัญชีผู้ใช้ LIFX ของคุณเชื่อมต่อกับ SmartThings แล้ว! -'''Click 'Done' to finish setup.'''=คลิก 'เสร็จสิ้น' เพื่อทำการตั้งค่าให้เสร็จสิ้น -'''The connection could not be established!'''=ไม่สามารถสร้างการเชื่อมต่อได้! -'''Click 'Done' to return to the menu.'''=คลิก 'เสร็จสิ้น' เพื่อกลับไปยังเมนู -'''Your LIFX Account is already connected to SmartThings!'''=บัญชีผู้ใช้ LIFX ของคุณเชื่อมต่อกับ SmartThings อยู่แล้ว! -'''Click 'Done' to finish setup.'''=คลิก 'เสร็จสิ้น' เพื่อทำการตั้งค่าให้เสร็จสิ้น -'''SmartThings Connection'''=การเชื่อมต่อ SmartThings -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=อุปกรณ์จะถูกเพิ่มโดยอัตโนมัติจากบัญชีผู้ใช้ LIFX ของคุณ ในการเพิ่มหรือลบอุปกรณ์ โปรดใช้แอพ LIFX ที่เป็นทางการ -'''Set for specific mode(s)'''=ตั้งค่าสำหรับโหมดเฉพาะแล้ว -'''Assign a name'''=กำหนดชื่อ -'''Tap to set'''=แตะเพื่อตั้งค่า -'''Phone'''=เบอร์โทรศัพท์ -'''Which?'''=รายการใด -'''Add a name'''=เพิ่มชื่อ -'''Tap to choose'''=แตะเพื่อเลือก -'''Choose an icon'''=เลือกไอคอน -'''Next page'''=หน้าถัดไป -'''Text'''=ข้อความ -'''Number'''=หมายเลข diff --git a/smartapps/smartthings/lifx-connect.src/i18n/tr-TR.properties b/smartapps/smartthings/lifx-connect.src/i18n/tr-TR.properties deleted file mode 100644 index cee7a472973..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/tr-TR.properties +++ /dev/null @@ -1,27 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=LIFX akıllı ampulleri SmartThings ile birlikte kullanabilmenizi sağlar. -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=LIFX kimlik bilgilerini girmek için dokunun -'''Connect to LIFX'''=LIFX'e bağlan -'''Tap here to connect your LIFX account'''=LIFX hesabınıza bağlanmak için buraya dokunun -'''Connect to LIFX'''=LIFX'e bağlan -'''Select your location'''=Konumunuzu seçin -'''Select location ({{count}} found)'''=Konum seçin ({{count}} bulundu) -'''Your LIFX Account is now connected to SmartThings!'''=LIFX Hesabınız artık SmartThings'e bağlandı! -'''Click 'Done' to finish setup.'''=Kurulumu bitirmek için 'Bitti' öğesine tıklayın. -'''The connection could not be established!'''=Bağlantı kurulamadı! -'''Click 'Done' to return to the menu.'''=Menüye dönmek için 'Bitti' öğesine tıklayın. -'''Your LIFX Account is already connected to SmartThings!'''=LIFX Hesabınız zaten SmartThings'e bağlı! -'''Click 'Done' to finish setup.'''=Kurulumu bitirmek için 'Bitti' öğesine tıklayın. -'''SmartThings Connection'''=SmartThings Bağlantısı -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=Cihazlar LIFX hesabınızdan otomatik olarak eklenecek. Cihaz eklemek veya silmek için lütfen Resmi LIFX Uygulamasını kullanın -'''Set for specific mode(s)'''=Belirli modlar belirleyin -'''Assign a name'''=İsim atayın -'''Tap to set'''=Ayarlamak için dokunun -'''Phone'''=Telefon Numarası -'''Which?'''=Hangisi? -'''Add a name'''=Bir isim ekle -'''Tap to choose'''=Seçmek için dokun -'''Choose an icon'''=Bir simge seç -'''Next page'''=Sonraki Sayfa -'''Text'''=Metin -'''Number'''=Numara diff --git a/smartapps/smartthings/lifx-connect.src/i18n/zh-CN.properties b/smartapps/smartthings/lifx-connect.src/i18n/zh-CN.properties deleted file mode 100644 index c4dc475b9aa..00000000000 --- a/smartapps/smartthings/lifx-connect.src/i18n/zh-CN.properties +++ /dev/null @@ -1,21 +0,0 @@ -'''Allows you to use LIFX smart light bulbs with SmartThings.'''=允许您将 LIFX 智能灯泡与 SmartThings 一起使用。 -'''LIFX'''=LIFX -'''Tap to enter LIFX credentials'''=点击以输入 LIFX 凭据 -'''Connect to LIFX'''=连接至 LIFX -'''Tap here to connect your LIFX account'''=点击此处连接 LIFX 帐户 -'''Connect to LIFX'''=连接至 LIFX -'''Select your location'''=选择您的位置 -'''Select location ({{count}} found)'''=选择位置 (发现 {{count}} 个) -'''Your LIFX Account is now connected to SmartThings!'''=LIFX 帐户现在已连接至 SmartThings! -'''Click 'Done' to finish setup.'''=单击“完成”以完成设置。 -'''The connection could not be established!'''=无法建立连接! -'''Click 'Done' to return to the menu.'''=单击“完成”返回菜单。 -'''Your LIFX Account is already connected to SmartThings!'''=LIFX 帐户现在已连接至 SmartThings! -'''Click 'Done' to finish setup.'''=单击“完成”以完成设置。 -'''SmartThings Connection'''=SmartThings 连接 -'''Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App.'''=设备将从LIFX帐户中自动添加。要添加或删除设备,请使用LIFX应用程序 -'''Set for specific mode(s)'''=设置特定模式 -'''Assign a name'''=分配名称 -'''Tap to set'''=点击以设置 -'''Phone'''=电话号码 -'''Which?'''=哪个? diff --git a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy b/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy deleted file mode 100644 index 7437b4821dd..00000000000 --- a/smartapps/smartthings/lifx-connect.src/lifx-connect.groovy +++ /dev/null @@ -1,540 +0,0 @@ -/** - * LIFX - * - * Copyright 2015 LIFX - * - */ -include 'localization' -include 'cirrus' - -definition( - name: "LIFX (Connect)", - namespace: "smartthings", - author: "LIFX", - description: "Allows you to use LIFX smart light bulbs with SmartThings.", - category: "Convenience", - iconUrl: "https://cloud.lifx.com/images/lifx.png", - iconX2Url: "https://cloud.lifx.com/images/lifx.png", - iconX3Url: "https://cloud.lifx.com/images/lifx.png", - oauth: true, - singleInstance: true, - usesThirdPartyAuthentication: true, - pausable: false -) { - appSetting "clientId" - appSetting "clientSecret" - appSetting "serverUrl" // See note below -} - -// NOTE regarding OAuth settings. On NA01 (i.e. graph.api), NA01S, and NA01D the serverUrl app setting can be left -// Blank. For other shards is should be set to the callback URL registered with LIFX, which is: -// -// Production -- https://graph.api.smartthings.com -// Staging -- https://graph-na01s-useast1.smartthingsgdev.com -// Development -- https://graph-na01d-useast1.smartthingsgdev.com - -preferences { - page(name: "Credentials", title: "LIFX", content: "authPage", install: true) -} - -mappings { - path("/receivedToken") { action: [ POST: "oauthReceivedToken", GET: "oauthReceivedToken"] } - path("/receiveToken") { action: [ POST: "oauthReceiveToken", GET: "oauthReceiveToken"] } - path("/webhookCallback") { action: [ POST: "webhookCallback"] } - path("/oauth/callback") { action: [ GET: "oauthCallback" ] } - path("/oauth/initialize") { action: [ GET: "oauthInit"] } - path("/test") { action: [ GET: "oauthSuccess" ] } -} - -def getServerUrl() { return appSettings.serverUrl ?: apiServerUrl } -def getCallbackUrl() { return "${getServerUrl()}/oauth/callback" } -def apiURL(path = '/') { return "https://api.lifx.com/v1${path}" } -def getSecretKey() { return appSettings.secretKey } -def getClientId() { return appSettings.clientId } -def getVendorName() { "LIFX" } - -def authPage() { - if (state.lifxAccessToken) { - def validateToken = locationOptions() ?: [] - } - - if (!state.lifxAccessToken) { - log.debug "no LIFX access token" - // This is the SmartThings access token - if (!state.accessToken) { - log.debug "no access token, create access token" - state.accessToken = createAccessToken() // predefined method - } - def description = "Tap to enter LIFX credentials" - def redirectUrl = "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" // this triggers oauthInit() below - return dynamicPage(name: "Credentials", title: "Connect to LIFX", nextPage: null, uninstall: true, install:true) { - section { - href(url:redirectUrl, required:true, title:"Connect to LIFX", description:"Tap here to connect your LIFX account") - } - } - } else { - log.debug "have LIFX access token" - - def options = locationOptions() ?: [] - def count = options.size().toString() - - return dynamicPage(name:"Credentials", title:"", nextPage:"", install:true, uninstall: true) { - section("Select your location") { - input "selectedLocationId", "enum", required:true, title:"Select location ({{count}} found)", messageArgs: [count: count], multiple:false, options:options, submitOnChange: true - paragraph "Devices will be added automatically from your LIFX account. To add or delete devices please use the Official LIFX App." - } - } - } -} - -// OAuth - -def oauthInit() { - def oauthParams = [client_id: "${appSettings.clientId}", scope: "remote_control:all", response_type: "code" ] - log.debug("Redirecting user to OAuth setup") - redirect(location: "https://cloud.lifx.com/oauth/authorize?${toQueryString(oauthParams)}") -} - -def oauthCallback() { - def redirectUrl = null - if (params.authQueryString) { - redirectUrl = URLDecoder.decode(params.authQueryString.replaceAll(".+&redirect_url=", "")) - } else { - log.warn "No authQueryString" - } - - if (state.lifxAccessToken) { - log.debug "Access token already exists" - success() - } else { - def code = params.code - if (code) { - if (code.size() > 6) { - // LIFX code - log.debug "Exchanging code for access token" - oauthReceiveToken(redirectUrl) - } else { - // Initiate the LIFX OAuth flow. - oauthInit() - } - } else { - log.debug "This code should be unreachable" - success() - } - } -} - -def oauthReceiveToken(redirectUrl = null) { - // Not sure what redirectUrl is for - log.debug "receiveToken - params: ${params}" - def oauthParams = [ client_id: "${appSettings.clientId}", client_secret: "${appSettings.clientSecret}", grant_type: "authorization_code", code: params.code, scope: params.scope ] // how is params.code valid here? - def params = [ - uri: "https://cloud.lifx.com/oauth/token", - body: oauthParams, - headers: [ - "User-Agent": "SmartThings Integration" - ] - ] - httpPost(params) { response -> - state.lifxAccessToken = response.data.access_token - } - - if (state.lifxAccessToken) { - oauthSuccess() - } else { - oauthFailure() - } -} - -def oauthSuccess() { - def message = """ -

Your LIFX Account is now connected to SmartThings!

-

Click 'Done' to finish setup.

- """ - oauthConnectionStatus(message) -} - -def oauthFailure() { - def message = """ -

The connection could not be established!

-

Click 'Done' to return to the menu.

- """ - oauthConnectionStatus(message) -} - -def oauthReceivedToken() { - def message = """ -

Your LIFX Account is already connected to SmartThings!

-

Click 'Done' to finish setup.

- """ - oauthConnectionStatus(message) -} - -def oauthConnectionStatus(message, redirectUrl = null) { - def redirectHtml = "" - if (redirectUrl) { - redirectHtml = """ - - """ - } - - def html = """ - - - - - SmartThings Connection - - ${redirectHtml} - - -
- LIFX icon - connected device icon - SmartThings logo -

- ${message} -

-
- - - """ - render contentType: 'text/html', data: html -} - -String toQueryString(Map m) { - return m.collect { k, v -> "${k}=${URLEncoder.encode(v.toString())}" }.sort().join("&") -} - -// App lifecycle hooks - -def installed() { - if (!state.accessToken) { - createAccessToken() - } else { - initialize() - } -} - -// called after settings are changed -def updated() { - if (!state.accessToken) { - createAccessToken() - } else { - initialize() - } -} - -def uninstalled() { - cirrus.unregisterServiceManager() -} - -// called after Done is hit after selecting a Location -def initialize() { - log.debug "initialize" - - if (cirrusEnabled) { - // Create the devices - updateDevicesFromResponse(devicesInLocation()) - - // Sync with Cirrus once per day to ensure consistency and maintain polling by Gadfly - runDaily(new Date(), registerWithCirrus) - } - else { - // Create the devices and generate events for their initial state - updateDevices() - - // Check for new devices and remove old ones every 3 hours - runEvery5Minutes('updateDevices') - } - setupDeviceWatch() -} - -// Misc -def setupDeviceWatch() { - def hub = location.hubs[0] - // Make sure that all child devices are enrolled in device watch - getChildDevices().each { - it.sendEvent(name: "DeviceWatch-Enroll", value: "{\"protocol\": \"LAN\", \"scheme\":\"untracked\", \"hubHardwareId\": \"${hub?.hub?.hardwareID}\"}") - } -} - -Map apiRequestHeaders() { - return ["Authorization": "Bearer ${state.lifxAccessToken}", - "Accept": "application/json", - "Content-Type": "application/json", - "User-Agent": "SmartThings Integration" - ] -} - -// Requests -def logResponse(response) { - log.debug("Status: ${response.status}") - log.debug("Body: ${response.data}") -} - -// API Requests -// logObject is because log doesn't work if this method is being called from a Device -def logErrors(options = [errorReturn: null, logObject: log], Closure c) { - try { - return c() - } catch (groovyx.net.http.HttpResponseException e) { - options.logObject.error("got error: ${e}, body: ${e.getResponse().getData()}") - if (e.statusCode == 401) { // token is expired - state.lifxAccessToken = null - options.logObject.warn "Access token is not valid" - } - return options.errorReturn - } catch (java.net.SocketTimeoutException e) { - options.logObject.warn "Connection timed out, not much we can do here" - return options.errorReturn - } -} - -def apiGET(path) { - try { - httpGet(uri: apiURL(path), headers: apiRequestHeaders()) {response -> - if (response.status == 401) { // token is expired - log.warn "Access token is not valid" - state.lifxAccessToken = null - } - logResponse(response) - return response - } - } catch (groovyx.net.http.HttpResponseException e) { - logResponse(e.response) - return e.response - } -} - -def apiPUT(path, body = [:]) { - try { - log.debug("Beginning API PUT: ${path}, ${body}") - httpPutJson(uri: apiURL(path), body: new groovy.json.JsonBuilder(body).toString(), headers: apiRequestHeaders(), ) {response -> - if (response.status == 401) { // token is expired - log.warn "Access token is not valid" - state.lifxAccessToken = null - } - logResponse(response) - return response - } - } catch (groovyx.net.http.HttpResponseException e) { - logResponse(e.response) - return e.response - } -} - -def devicesList(selector = '') { - logErrors([]) { - def resp = apiGET("/lights/${selector}") - if (resp.status == 200) { - return resp.data - } else if (resp.status == 401) { - log.warn "Access token is not valid" - state.lifxAccessToken = null - } else if (resp.status == 404 && resp.data?.error.startsWith('Could not find location_id') && selector != '') { - log.warn "Location is not valid" - def devices = devicesList() - devices.each { device -> - if (device.location.id != settings.selectedLocationId && getChildDevice(device.id)) { - settings.selectedLocationId = device.location.id - app.updateSetting("selectedLocationId", device.location.id) - } - } - } else { - String errMsg = "No response from device list call. ${resp.status} ${resp.data}" - log.debug(errMsg) - throw new java.lang.RuntimeException(errMsg) - } - } -} - -Map locationOptions() { - def options = [:] - def devices = devicesList() - devices.each { device -> - options[device.location.id] = device.location.name - } - log.debug("Locations: ${options}") - return options -} - -def devicesInLocation() { - return devicesList("location_id:${settings.selectedLocationId}") -} - -def webhookCallback() { - log.debug "webhookCallback" - def data = request.JSON - log.debug data - if (data) { - updateDevicesFromResponse(data) - [status: "ok", source: "smartApp"] - } else { - [status: "operation not defined", source: "smartApp"] - } -} - -// Cirrus version that only creates and deletes devices, since Cirrus and Gadfly are responsible for updating -void updateDevicesFromResponse(devices) { - log.debug("updateDevicesFromResponse(${devices.size()})") - def changed = false - def deviceIds = [] - def children = getChildDevices() - devices.each { device -> - deviceIds << device.id - def childDevice = children.find {it.deviceNetworkId == device.id} - if (!childDevice) { - log.trace "adding child device $device.label" - if (device.product.capabilities.has_color) { - addChildDevice(app.namespace, "LIFX Color Bulb", device.id, null, ["label": device.label, "completedSetup": true]) - } else { - addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, ["label": device.label, "completedSetup": true]) - } - changed = true - } - } - - children.findAll { !deviceIds.contains(it.deviceNetworkId) }.each { - log.trace "deleting child device $it.label" - deleteChildDevice(it.deviceNetworkId) - changed = true - } - - if (changed) { - // Run in a separate sandbox instance because caching issues can prevent children from being picked up - runIn(1, registerWithCirrus) - } -} - -// Non-Cirrus version that updates devices and generates events -void updateDevices() { - if (cirrusEnabled) { - switchToCirrus() - return - } - - if (!state.devices) { - state.devices = [:] - } - def devices = devicesInLocation() - def selectors = [] - - log.debug("All selectors: ${selectors}") - - devices.each { device -> - def childDevice = getChildDevice(device.id) - selectors.add("${device.id}") - if (!childDevice) { - // log.info("Adding device ${device.id}: ${device.product}") - if (device.product.capabilities.has_color) { - childDevice = addChildDevice(app.namespace, "LIFX Color Bulb", device.id, null, ["label": device.label, "completedSetup": true]) - } else { - childDevice = addChildDevice(app.namespace, "LIFX White Bulb", device.id, null, ["label": device.label, "completedSetup": true]) - } - } - - if (device.product.capabilities.has_color) { - childDevice.sendEvent(name: "color", value: colorUtil.hslToHex((device.color.hue / 3.6) as int, (device.color.saturation * 100) as int)) - childDevice.sendEvent(name: "hue", value: device.color.hue / 3.6) - childDevice.sendEvent(name: "saturation", value: device.color.saturation * 100) - } - childDevice.sendEvent(name: "label", value: device.label) - childDevice.sendEvent(name: "level", value: Math.round((device.brightness != null ? device.brightness : 1) * 100)) - childDevice.sendEvent(name: "switch", value: device.power) - childDevice.sendEvent(name: "colorTemperature", value: device.color.kelvin) - childDevice.sendEvent(name: "model", value: device.product.name) - - if (state.devices[device.id] == null) { - // State missing, add it and set it to opposite status as current status to provoke event below - state.devices[device.id] = [online: !device.connected] - } - - if (!state.devices[device.id]?.online && device.connected) { - // Device came online after being offline - childDevice?.sendEvent(name: "DeviceWatch-DeviceStatus", value: "online", displayed: false) - log.debug "$device is back Online" - } else if (state.devices[device.id]?.online && !device.connected) { - // Device went offline after being online - childDevice?.sendEvent(name: "DeviceWatch-DeviceStatus", value: "offline", displayed: false) - log.debug "$device went Offline" - } - state.devices[device.id] = [online: device.connected] - } - getChildDevices().findAll { !selectors.contains("${it.deviceNetworkId}") }.each { - log.debug("Deleting ${it.deviceNetworkId}") - if (state.devices[it.deviceNetworkId]) - state.devices[it.deviceNetworkId] = null - // The reason the implementation is trying to delete this bulb is because it is not longer connected to the LIFX location. - // Adding "try" will prevent this exception from happening. - // Ideally device health would show to the user that the device is not longer accessible so that the user can either force delete it or remove it from the SmartApp. - try { - deleteChildDevice(it.deviceNetworkId) - } catch (Exception e) { - log.debug("Can't remove this device because it's being used by an SmartApp") - } - } -} - -boolean getCirrusEnabled() { - def result = cirrus.enabled("smartthings.cdh.handlers.LifxLightHandler") - log.debug "cirrusEnabled=$result" - result -} - -void switchToCirrus() { - log.info "Switching to cirrus" - registerWithCirrus() - unschedule() - runDaily(new Date(), registerWithCirrus) -} - -def registerWithCirrus() { - cirrus.registerServiceManager("smartthings.cdh.handlers.LifxLightHandler", [ - remoteAuthToken: state.lifxAccessToken, - lifxLocationId: settings.selectedLocationId, - ]) -}