diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..251dad2 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,156 @@ +## Contribution guidelines + +### Pull requests are always welcome + +We are always thrilled to receive pull requests, and do our best to +process them as fast as possible. Not sure if that typo is worth a pull +request? Do it! We will appreciate it. + +If your pull request is not accepted on the first try, don't be +discouraged! If there's a problem with the implementation, hopefully you +received feedback on what to improve. + +### Discuss your design on the mailing list + +We recommend discussing your plans [in the discussion forum](https://community.openhab.org/) +before starting to code - especially for more ambitious contributions. +This gives other contributors a chance to point you in the right +direction, give feedback on your design, and maybe point out if someone +else is working on the same thing. + +### Create issues... + +Any significant improvement should be documented as [a GitHub +issue](https://github.com/openhab/openhab-mycroft/issues?labels=enhancement&page=1&state=open) before anybody +starts working on it. + +### ...but check for existing issues first! + +Please take a moment to check that an issue doesn't already exist +documenting your bug report or improvement proposal. If it does, it +never hurts to add a quick "+1" or "I have this problem too". This will +help prioritize the most common problems and requests. + +### Conventions + +Fork the repo and make changes on your fork in a feature branch. + +Update the documentation when creating or modifying features. Test +your documentation changes for clarity, concision, and correctness, as +well as a clean documentation build. + +Write clean code. Universally formatted code promotes ease of writing, reading, +and maintenance. + +Pull requests descriptions should be as clear as possible and include a +reference to all the issues that they address. + +Pull requests must not contain commits from other users or branches. + +Commit messages must start with a capitalized and short summary (max. 50 +chars) written in the imperative, followed by an optional, more detailed +explanatory text which is separated from the summary by an empty line. + +Code review comments may be added to your pull request. Discuss, then make the +suggested modifications and push additional commits to your feature branch. Be +sure to post a comment after pushing. The new commits will show up in the pull +request automatically, but the reviewers will not be notified unless you +comment. + +Before the pull request is merged, make sure that you squash your commits into +logical units of work using `git rebase -i` and `git push -f`. After every +commit the test suite should be passing. Include documentation changes in the +same commit so that a revert would remove all traces of the feature or fix. + +Commits that fix or close an issue should include a reference like `Closes #XXX` +or `Fixes #XXX`, which will automatically close the issue when merged. + +### Merge approval + +openHAB-Mycroft maintainers use LGTM (Looks Good To Me) in comments on the code review +to indicate acceptance. + +### Sign your work + +The sign-off is a simple line at the end of the explanation for the +patch, which certifies that you wrote it or otherwise have the right to +pass it on as an open-source patch. The rules are pretty simple: if you +can certify the below (from +[developercertificate.org](http://developercertificate.org/)): + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +660 York Street, Suite 102, +San Francisco, CA 94110 USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +then you just add a line to every git commit message: + + Signed-off-by: Joe Smith (github: github_handle) + +using your real name (sorry, no pseudonyms or anonymous contributions.) + +#### Small patch exception + +There are several exceptions to the signing requirement. Currently these are: + +* Your patch fixes spelling or grammar errors. +* Your patch is a single line change to documentation. + +## Community Guidelines + +We want to keep the openHAB-Mycroft community awesome, growing and collaborative. We +need your help to keep it that way. To help with this we've come up with some +general guidelines for the community as a whole: + +* Be nice: Be courteous, respectful and polite to fellow community members: no + regional, racial, gender, or other abuse will be tolerated. We like nice people + way better than mean ones! + +* Encourage diversity and participation: Make everyone in our community + feel welcome, regardless of their background and the extent of their + contributions, and do everything possible to encourage participation in + our community. + +* Keep it legal: Basically, don't get us in trouble. Share only content that + you own, do not share private or sensitive information, and don't break the + law. + +* Stay on topic: Make sure that you are posting to the correct channel + and avoid off-topic discussions. Remember when you update an issue or + respond to an email you are potentially sending to a large number of + people. Please consider this before you update. Also remember that + nobody likes spam. diff --git a/README.md b/README.md new file mode 100644 index 0000000..11f9229 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# openHAB skill for Mycroft + +This skill adds [openHAB](http://www.openhab.org/) support to [Mycroft](https://mycroft.ai). +The skill takes advantage of the openHAB REST API, so it works both with the v1.x and v2.x of openHAB. + +Some sample voice commands are: + +- *"Hey Mycroft, turn on Diningroom Light"* +- *"Hey Mycroft, switch off Kitchen Light"* +- *"Hey Mycroft, put on Good Night"* +- *"Hey Mycroft, set Diningroom to 50 percent"* +- *"Hey Mycroft, dim Kitchen"* +- *"Hey Mycroft, brighten Kitchen"* +- *"Hey Mycroft, dim Kitchen by 20 percent"* +- *"Hey Mycroft, what's Bedroom temperature?"* +- *"Hey Mycroft, what's Bedroom humidity?"* +- *"Hey Mycroft, adjust Main Thermostat to 21 degrees"* +- *"Hey Mycroft, regulate Main Thermostat to 20 degrees"* +- *"Hey Mycroft, decrease Main Thermostat by 2 degrees"* +- *"Hey Mycroft, increase Main Thermostat by 1 degrees"* +- *"Hey Mycroft, what is Main Thermostat regulated to?"* +- *"Hey Mycroft, what is Main Thermostat tuned to?"* + +## openHAB Item Configuration + +In order to make openHAB Items accessible to Mycroft, they need to be [tagged](http://docs.openhab.org/addons/io/homekit/readme.html). +Device names recognized by Mycroft are matched against openHAB Item Labels. + +The above examples would all work with the following set of openHAB Item definitons: + +```java +Color DiningroomLight "Diningroom Light" (gKitchen) [ "Lighting" ] {channel="hue:0200:1:bloom1:color"} +Color KitchenLight "Kitchen Light" (gKitchen) [ "Lighting" ] {channel="hue:0200:1:bloom1:color"} +Switch GoodNight "Good Night" [ "Switchable" ] + +Number MqttID1Temperature "Bedroom Temperature" [ "CurrentTemperature" ] {mqtt="<[mosquitto:mysensors/SI/1/1/1/0/0:state:default]"} +Number MqttID1Humidity "Bedroom Humidity" [ "CurrentHumidity" ] {mqtt="<[mosquitto:mysensors/SI/1/0/1/0/1:state:default]"} + +Group gThermostat "Main Thermostat" [ "gMainThermostat" ] +Number MainThermostatCurrentTemp "Main Thermostat Current Temperature" (gMainThermostat) [ "CurrentTemperature" ] +Number MainThermostatTargetTemperature "Main Thermostat Target Temperature" (gMainThermostat) [ "TargetTemperature" ] +String MainThermostatHeatingCoolingMode "Main Thermostat Heating/Cooling Mode" (gMainThermostat) [ "homekit:HeatingCoolingMode" ] +``` + +If items are modified in openHAB, a refresh in Mycroft is needed by the command: + +- *"Hey Mycroft, refresh openhab items"* + +## Versions Change Log +* 1.0 added support to item tagged as Thermostat, CurrentTemperature, CurrentHumidity +* 0.9 added dimming command to item tagged as Lighting +* 0.8 supports only Lighting and Switchable tags, commands ON and OFF + +## Installation + +Clone this repository into your `~/.mycroft/skills` directory. +Then install the dependencies inside your mycroft virtual environment: + +If on picroft just skip the workon part and the directory will be `/opt/mycroft/skills` + +```shell +cd ~/.mycroft/skills +git clone https://github.com/mortommy/mycroft-skill-openhab skill-openhab +workon mycroft +cd skill-openhab +pip install -r requirements.txt +``` + +### Configuration + +Add the block below to your `mycoft.conf` file: + +```json + "openHABSkill": { + "host": "openHAB server ip", + "port": "openHAB server port" + } +``` + +Restart mycroft for the changes to take effect. diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..1c570cb --- /dev/null +++ b/__init__.py @@ -0,0 +1,321 @@ +# Copyright (c) 2010-2017 by the respective copyright holders. + +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html + +from os.path import dirname + +from adapt.intent import IntentBuilder +from mycroft.skills.core import MycroftSkill +from mycroft.util.log import getLogger +from fuzzywuzzy import fuzz + +import requests +import json + +# v 0.1 - just switch on and switch off a fix light +# v 0.2 - code review +# v 0.3 - first working version on fixed light item +# v 0.4 - getTaggedItems method in order to get all the tagged items from openHAB +# v 0.5 - refresh tagged item intent +# v 0.6 - add findItemName method and import fuzzywuzzy +# v 0.7 - add intent for switchable items +# v 0.8 - merged lighting and switchable intent in onoff intent +# v 0.9 - added support to dimmable items +# v 1.0 - added Thermostat tag support + +__author__ = 'mortommy' + +LOGGER = getLogger(__name__) + +class openHABSkill(MycroftSkill): + + def __init__(self): + super(openHABSkill, self).__init__(name="openHABSkill") + + self.url = "http://%s:%s/rest" % (self.config.get('host'), self.config.get('port')) + + self.command_headers = {"Content-type": "text/plain"} + + self.polling_headers = {"Accept": "application/json"} + + self.lightingItemsDic = dict() + self.switchableItemsDic = dict() + self.currentTempItemsDic = dict() + self.currentHumItemsDic = dict() + #self.currentThermostatItemsDic = dict() + self.targetTemperatureItemsDic = dict() + #self.homekitHeatingCoolingModeDic = dict() + + self.getTaggedItems() + + def initialize(self): + + refresh_tagged_items_intent = IntentBuilder("RefreshTaggedItemsIntent").require("RefreshTaggedItemsKeyword").build() + self.register_intent(refresh_tagged_items_intent, self.handle_refresh_tagged_items_intent) + + onoff_status_intent = IntentBuilder("OnOff_StatusIntent").require("OnOffStatusKeyword").require("Command").require("Item").build() + self.register_intent(onoff_status_intent, self.handle_onoff_status_intent) + + dimmer_status_intent = IntentBuilder("Dimmer_StatusIntent").require("DimmerStatusKeyword").require("Item").optionally("BrigthPercentage").build() + self.register_intent(dimmer_status_intent, self.handle_dimmer_status_intent) + + what_status_intent = IntentBuilder("What_StatusIntent").require("WhatStatusKeyword").require("Item").require("RequestType").build() + self.register_intent(what_status_intent, self.handle_what_status_intent) + + setTemp_status_intent = IntentBuilder("SetTemp_StatusIntent").require("ThermostatStatusKeyword").require("Item").require("TempValue").build() + self.register_intent(setTemp_status_intent, self.handle_setTemp_status_intent) + + def getTaggedItems(self): + #find all the items tagged Lighting and Switchable from openHAB + #the labeled items are stored in dictionaries + + self.lightingItemsDic = {} + self.switchableItemsDic = {} + self.currentTempItemsDic = {} + self.currentHumItemsDic = {} + self.currentThermostatItemsDic = {} + self.targetTemperatureItemsDic = {} + self.homekitHeatingCoolingModeDic = {} + + requestUrl = self.url+"/items?recursive=false" + + try: + req = requests.get(requestUrl, headers=self.polling_headers) + if req.status_code == 200: + json_response = req.json() + for x in range(0,len(json_response)): + if ("Lighting" in json_response[x]['tags']): + self.lightingItemsDic.update({json_response[x]['name']: json_response[x]['label']}) + elif ("Switchable" in json_response[x]['tags']): + self.switchableItemsDic.update({json_response[x]['name']: json_response[x]['label']}) + elif ("CurrentTemperature" in json_response[x]['tags']): + self.currentTempItemsDic.update({json_response[x]['name']: json_response[x]['label']}) + elif ("CurrentHumidity" in json_response[x]['tags']): + self.currentHumItemsDic.update({json_response[x]['name']: json_response[x]['label']}) + elif ("Thermostat" in json_response[x]['tags']): + self.currentThermostatItemsDic.update({json_response[x]['name']: json_response[x]['label']}) + elif ("TargetTemperature" in json_response[x]['tags']): + self.targetTemperatureItemsDic.update({json_response[x]['name']: ""}) + elif ("homekit:HeatingCoolingMode" in json_response[x]['tags']): + self.homekitHeatingCoolingModeDic.update({json_response[x]['name']: json_response[x]['label']}) + else: + pass + else: + LOGGER.error("Some issues with the command execution!") + self.speak_dialog('GetItemsListError') + + except KeyError: + pass + + def findItemName(self, itemDictionary, messageItem): + + bestScore = 0 + score = 0 + bestItem = None + + try: + for itemName, itemLabel in itemDictionary.items(): + score = fuzz.ratio(messageItem, itemLabel) + if score > bestScore: + bestScore = score + bestItem = itemName + except KeyError: + pass + + return bestItem + + def handle_refresh_tagged_items_intent(self, message): + #to refresh the openHAB items labeled list we use an intent, we can ask Mycroft to make the refresh + + self.getTaggedItems() + dictLenght = str(len(self.lightingItemsDic) + len(self.switchableItemsDic) + len(self.currentTempItemsDic) + len(self.currentHumItemsDic) + len(self.currentThermostatItemsDic) + len(self.targetTemperatureItemsDic) + len(self.homekitHeatingCoolingModeDic)) + self.speak_dialog('RefreshTaggedItems', {'number_item': dictLenght}) + + def handle_onoff_status_intent(self, message): + command = message.data.get('Command') + messageItem = message.data.get('Item') + + #We have to find the item to update from our dictionaries + self.lightingSwitchableItemsDic = dict() + self.lightingSwitchableItemsDic.update(self.lightingItemsDic) + self.lightingSwitchableItemsDic.update(self.switchableItemsDic) + + ohItem = self.findItemName(self.lightingSwitchableItemsDic, messageItem) + + if ohItem != None: + if (command != "on") and (command != "off"): + self.speak_dialog('ErrorDialog') + else: + statusCode = self.sendCommandToItem(ohItem, command.upper()) + if statusCode == 200: + self.speak_dialog('StatusOnOff', {'command': command, 'item': messageItem}) + elif statusCode == 404: + LOGGER.error("Some issues with the command execution!. Item not found") + self.speak_dialog('ItemNotFoundError') + else: + LOGGER.error("Some issues with the command execution!") + self.speak_dialog('CommunicationError') + else: + LOGGER.error("Item not found!") + self.speak_dialog('ItemNotFoundError') + + def handle_dimmer_status_intent(self, message): + command = message.data.get('DimmerStatusKeyword') + messageItem = message.data.get('Item') + brightValue = message.data.get('BrigthPercentage', None) + + statusCode = 0 + newBrightValue = 0 + + ohItem = self.findItemName(self.lightingItemsDic, messageItem) + + if ohItem != None: + if (command == "set"): + if ((int(brightValue) < 0) or (int(brightValue) > 100)): + self.speak_dialog('ErrorDialog') + else: + statusCode = self.sendCommandToItem(ohItem, brightValue) + else: + #find current item statusCode + state = self.getCurrentItemStatus(ohItem) + if (state != None): + #dim or brighten the value + curBrightList = state.split(',') + curBright = int(curBrightList[len(curBrightList)-1]) + + if(brightValue == None): + brightValue = "10" + + if (command == "dim"): + newBrightValue = curBright-(int(brightValue)) + else: + newBrightValue = curBright+(int(brightValue)) + + if (newBrightValue < 0): + newBrightValue = 0 + elif (newBrightValue > 100): + newBrightValue = 100 + else: + pass + + #send command to item + statusCode = self.sendCommandToItem(ohItem, str(newBrightValue)) + else: + pass + + if statusCode == 200: + self.speak_dialog('StatusDimmer', {'item': messageItem}) + elif statusCode == 404: + LOGGER.error("Some issues with the command execution!. Item not found") + self.speak_dialog('ItemNotFoundError') + else: + LOGGER.error("Some issues with the command execution!") + self.speak_dialog('CommunicationError') + + else: + LOGGER.error("Item not found!") + self.speak_dialog('ItemNotFoundError') + + def handle_what_status_intent(self, message): + messageItem = message.data.get('Item') + requestType = message.data.get('RequestType') + unitOfMeasure = "degree" + infoType = "temperature" + + self.currStatusItemsDic = dict() + + if(requestType == "temperature"): + self.currStatusItemsDic.update(self.currentTempItemsDic) + elif(requestType == "humidity"): + unitOfMeasure = "percentage" + infoType = "humidity" + self.currStatusItemsDic.update(self.currentHumItemsDic) + else: + self.currStatusItemsDic.update(self.targetTemperatureItemsDic) + + ohItem = self.findItemName(self.currStatusItemsDic, messageItem) + + if ohItem != None: + state = self.getCurrentItemStatus(ohItem) + self.speak_dialog('TempHumStatus', {'item': messageItem, 'temp_hum': infoType, 'temp_hum_val': state, 'units_of_measurement': unitOfMeasure}) + else: + LOGGER.error("Item not found!") + self.speak_dialog('ItemNotFoundError') + + def handle_setTemp_status_intent(self, message): + command = message.data.get('ThermostatStatusKeyword') + messageItem = message.data.get('Item') + tempVal = message.data.get('TempValue') + + statusCode = 0 + newTempValue = 0 + + ohItem = self.findItemName(self.targetTemperatureItemsDic, messageItem) + + if ohItem != None: + if((command == "regulate") or (command == "adjust") or (command == "tune")): + statusCode = self.sendCommandToItem(ohItem, tempVal) + newTempValue = tempVal + else: + state = self.getCurrentItemStatus(ohItem) + if ((state != None) and (state.isdigit())): + if (command == "increase"): + newTempValue = int(state)+(int(tempVal)) + else: + newTempValue = int(state)-(int(tempVal)) + + statusCode = self.sendCommandToItem(ohItem, str(newTempValue)) + else: + pass + + if statusCode == 200: + self.speak_dialog('ThermostatStatus', {'item': messageItem, 'temp_val': str(newTempValue)}) + elif statusCode == 404: + LOGGER.error("Some issues with the command execution!. Item not found") + self.speak_dialog('ItemNotFoundError') + else: + LOGGER.error("Some issues with the command execution!") + self.speak_dialog('CommunicationError') + + else: + LOGGER.error("Item not found!") + self.speak_dialog('ItemNotFoundError') + + def sendStatusToItem(self, ohItem, command): + requestUrl = self.url+"/items/%s/state" % (ohItem) + req = requests.put(requestUrl, data=command, headers=self.command_headers) + + return req.status_code + + def sendCommandToItem(self, ohItem, command): + requestUrl = self.url+"/items/%s" % (ohItem) + req = requests.post(requestUrl, data=command, headers=self.command_headers) + + return req.status_code + + def getCurrentItemStatus(self, ohItem): + requestUrl = self.url+"/items/%s/state" % (ohItem) + state = None + + try: + req = requests.get(requestUrl, headers=self.command_headers) + + if req.status_code == 200: + state = req.text + else: + LOGGER.error("Some issues with the command execution!") + self.speak_dialog('CommunicationError') + + except KeyError: + pass + + return state + + def stop(self): + pass + +def create_skill(): + return openHABSkill() \ No newline at end of file diff --git a/dialog/en-us/CommunicationError.dialog b/dialog/en-us/CommunicationError.dialog new file mode 100644 index 0000000..2f58304 --- /dev/null +++ b/dialog/en-us/CommunicationError.dialog @@ -0,0 +1 @@ +Sorry. Some problems with the command. diff --git a/dialog/en-us/ErrorDialog.dialog b/dialog/en-us/ErrorDialog.dialog new file mode 100644 index 0000000..478068d --- /dev/null +++ b/dialog/en-us/ErrorDialog.dialog @@ -0,0 +1,3 @@ +I don't know what to do +I don't understand +I'm lost \ No newline at end of file diff --git a/dialog/en-us/GetItemsListError.dialog b/dialog/en-us/GetItemsListError.dialog new file mode 100644 index 0000000..63084c9 --- /dev/null +++ b/dialog/en-us/GetItemsListError.dialog @@ -0,0 +1 @@ +Sorry cannot get the items list. \ No newline at end of file diff --git a/dialog/en-us/ItemNotFoundError.dialog b/dialog/en-us/ItemNotFoundError.dialog new file mode 100644 index 0000000..0ebf617 --- /dev/null +++ b/dialog/en-us/ItemNotFoundError.dialog @@ -0,0 +1 @@ +Sorry. Item not found in open hab. \ No newline at end of file diff --git a/dialog/en-us/RefreshTaggedItems.dialog b/dialog/en-us/RefreshTaggedItems.dialog new file mode 100644 index 0000000..06b4d73 --- /dev/null +++ b/dialog/en-us/RefreshTaggedItems.dialog @@ -0,0 +1 @@ +All right. I found {{number_item}} items. \ No newline at end of file diff --git a/dialog/en-us/StatusDimmer.dialog b/dialog/en-us/StatusDimmer.dialog new file mode 100644 index 0000000..6eb5e7d --- /dev/null +++ b/dialog/en-us/StatusDimmer.dialog @@ -0,0 +1 @@ +bright changed for {{item}} \ No newline at end of file diff --git a/dialog/en-us/StatusOnOff.dialog b/dialog/en-us/StatusOnOff.dialog new file mode 100644 index 0000000..159af4e --- /dev/null +++ b/dialog/en-us/StatusOnOff.dialog @@ -0,0 +1,3 @@ +put {{command}} {{item}} +switch {{command}} {{item}} +turn {{command}} {{item}} \ No newline at end of file diff --git a/dialog/en-us/TempHumStatus.dialog b/dialog/en-us/TempHumStatus.dialog new file mode 100644 index 0000000..68b8bf4 --- /dev/null +++ b/dialog/en-us/TempHumStatus.dialog @@ -0,0 +1 @@ +the {{item}} {{temp_hum}} is {{temp_hum_val}} {{units_of_measurement}} \ No newline at end of file diff --git a/dialog/en-us/ThermostatStatus.dialog b/dialog/en-us/ThermostatStatus.dialog new file mode 100644 index 0000000..90f119f --- /dev/null +++ b/dialog/en-us/ThermostatStatus.dialog @@ -0,0 +1,3 @@ +regulated {{item}} to {{temp_val}} degrees +adjusted {{item}} to {{temp_val}} degrees +tuned {{item}} to {{temp_val}} degrees \ No newline at end of file diff --git a/regex/en-us/dimmer_command.rx b/regex/en-us/dimmer_command.rx new file mode 100644 index 0000000..b920fa7 --- /dev/null +++ b/regex/en-us/dimmer_command.rx @@ -0,0 +1,2 @@ +(set) (?P.*) (to) (?P\d*)(?: percent)? +(dim|brighten) (?P.*?)\s*(?: by )?(?P\d*)?(?: percent)?$ \ No newline at end of file diff --git a/regex/en-us/onoff_command.rx b/regex/en-us/onoff_command.rx new file mode 100644 index 0000000..0e28f20 --- /dev/null +++ b/regex/en-us/onoff_command.rx @@ -0,0 +1 @@ +(turn|switch|put) (?Pon|off) (?P.*) diff --git a/regex/en-us/set_temp_status.rx b/regex/en-us/set_temp_status.rx new file mode 100644 index 0000000..9800a82 --- /dev/null +++ b/regex/en-us/set_temp_status.rx @@ -0,0 +1,2 @@ +(regulate|adjust|tune) (?P.*) (to) (?P\d*) (degrees) +(increase|decrease) (?P.*) (by) (?P\d*) (degrees) \ No newline at end of file diff --git a/regex/en-us/what_status.rx b/regex/en-us/what_status.rx new file mode 100644 index 0000000..a2ed456 --- /dev/null +++ b/regex/en-us/what_status.rx @@ -0,0 +1 @@ +(what is|what's) (?P.*) (?Ptemperature|humidity|adjusted to|regulated to|tuned to) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2485ffc --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +requests>=2.10.0 +fuzzywuzzy==0.14.0 +python-Levenshtein==0.12.0 \ No newline at end of file diff --git a/vocab/en-us/DimmerStatusKeyword.voc b/vocab/en-us/DimmerStatusKeyword.voc new file mode 100644 index 0000000..f51ba20 --- /dev/null +++ b/vocab/en-us/DimmerStatusKeyword.voc @@ -0,0 +1,3 @@ +set +dim +bright \ No newline at end of file diff --git a/vocab/en-us/OnOffStatusKeyword.voc b/vocab/en-us/OnOffStatusKeyword.voc new file mode 100644 index 0000000..c0fde2d --- /dev/null +++ b/vocab/en-us/OnOffStatusKeyword.voc @@ -0,0 +1,3 @@ +turn +switch +put \ No newline at end of file diff --git a/vocab/en-us/RefreshTaggedItemsKeyword.voc b/vocab/en-us/RefreshTaggedItemsKeyword.voc new file mode 100644 index 0000000..c03f2bd --- /dev/null +++ b/vocab/en-us/RefreshTaggedItemsKeyword.voc @@ -0,0 +1 @@ +refresh open hab items \ No newline at end of file diff --git a/vocab/en-us/ThermostatStatusKeyword.voc b/vocab/en-us/ThermostatStatusKeyword.voc new file mode 100644 index 0000000..3232c66 --- /dev/null +++ b/vocab/en-us/ThermostatStatusKeyword.voc @@ -0,0 +1,2 @@ +regulate|adjust|tune +increase|decrease \ No newline at end of file diff --git a/vocab/en-us/WhatStatusKeyword.voc b/vocab/en-us/WhatStatusKeyword.voc new file mode 100644 index 0000000..c81ed29 --- /dev/null +++ b/vocab/en-us/WhatStatusKeyword.voc @@ -0,0 +1,2 @@ +what is +what's \ No newline at end of file