Browse Source

alexa light switching

dirkse 8 years ago
parent
commit
fbd454dfcf
8 changed files with 141 additions and 23 deletions
  1. 7 2
      alexa/Dockerfile
  2. 16 0
      alexa/app/ameise.py
  3. 22 0
      alexa/app/chef.py
  4. 64 0
      alexa/app/domo.py
  5. 10 19
      alexa/app/server.py
  6. 13 0
      alexa/app/utils.py
  7. 6 1
      alexa/readme.md
  8. 3 1
      services.yml

+ 7 - 2
alexa/Dockerfile

@@ -5,13 +5,18 @@ RUN apt-get update && \
 
 ADD https://bootstrap.pypa.io/get-pip.py /tmp/get-pip.py
 RUN python /tmp/get-pip.py && \
-    pip install flask flask-ask unidecode
+    pip install flask unidecode
+
+#  decouble from flask-ask version changes
+RUN pip install cryptography==2.1.1 PyYAML==3.12  cffi==1.11.2 pycparser==2.18
+
+RUN pip install flask-ask==0.9.7 requests
 
 EXPOSE 80
 HEALTHCHECK --interval=10s CMD curl -sS --fail http://localhost:80 || exit 1
 
 CMD python -u /app/server.py
 
-COPY server.py /app/server.py
+COPY app /app
 
 

+ 16 - 0
alexa/app/ameise.py

@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+from __future__ import print_function, absolute_import, division, unicode_literals
+
+import logging
+
+from flask import Flask
+from flask_ask import Ask
+
+app = Flask(__name__)
+#~ app.config['ASK_PRETTY_DEBUG_LOGS'] = True
+app.config['ASK_APPLICATION_ID'] = 'amzn1.ask.skill.0d944823-e51c-47a3-bddb-5043d6d9f3eb'
+
+ask = Ask(app, "/ameise")
+
+log = logging.getLogger('flask_ask')
+log.setLevel(logging.INFO)

+ 22 - 0
alexa/app/chef.py

@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+from __future__ import print_function, absolute_import, division, unicode_literals
+
+import logging
+from random import choice
+
+from flask_ask import statement, question, session, context
+
+from ameise import app, ask, log
+
+
+@ask.intent("ChefIntent")
+def declare_chef():
+    names = ['Lilith', 'Elise', 'Lars', 'Annelie', 'Mama', 'Papa',
+            'Christine', 'Dirk', 'Lillutschka', 'Larsi', 'Liselchen', 'Annelutschka',
+            'Annelie Rothe', 'Lilith Rothe', 'Christine Rothe', 'Lars Rothe', 'Elise Rothe',
+            'die kleine Annelie', 'der schnelle Lars', 'die schlaue Elise', 'die intelligente Lilith']
+    chefs = ['Chef', 'Oberchef', 'Boss', 'Bestimmer', 'Meister',
+            'Leiter', 'Direktor', 'Anführer', 'Oberboss', 'König']
+    s = ('%s ist heute der %s, aber morgen ist %s dran!' %
+            (choice(names), choice(chefs), choice(names)))
+    return statement(s)

+ 64 - 0
alexa/app/domo.py

@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+from __future__ import print_function, absolute_import, division, unicode_literals
+import os
+
+import logging
+from timeit import default_timer
+import requests
+
+from ameise import app, ask, log
+
+from flask_ask import Ask, statement, question, session, context
+
+ALEXA_DEVICE2ROOM = {
+    'amzn1.ask.device.AGUM4ZB75QPFGNC5X2TYPIACRGBGQJUG7W3EJYVOG7W46XYQLQJNH3OJAUYPRZKMWDDE2UJGFJWSWCM27F4D22LD2PC6T3CAZEJB5ZQPIBY6NA32MIITTNUCTUL5SOIV5RDC2HWHI6UJRN77G7CFT2TPZB6A':
+        'arbeitszimmer',
+    'amzn1.ask.device.AGUM4ZB75QPFGNC5X2TYPIACRGBPSS5LVRD657YFVYBPGW2VGO2TZTHMZVAUBLBDSBKCTZ5P5MOXX5S5DLDEKPQAIOSQLQOI2SXIF2X6HT5GMJELOUNWZEXNM44SCT4CQBNTC73WDCW3KNX75PFXNFR7GRVA':
+        'wohnzimmer',
+    }
+
+# room powerswitch ids
+ROOM2POWER_DOMO_IDX = {
+    'arbeitszimmer': 2839,
+    'wohnzimmer': 2840,
+}
+
+# map alexa slot to domoticz switch value
+ON_OFF_SLOT = {'an': 'On', 'aus': 'Off'}
+
+
+DOMO_ALEXA_AUTH = ('alexa', os.environ['DOMO_ALEXA_PW'])
+DOMO_BASE = 'https://domo.cere.duckdns.org/json.htm'
+
+def domo_command(**kwargs):
+    t = default_timer()
+    try:
+        kwargs['type'] = 'command'
+        resp = requests.get(DOMO_BASE, params=kwargs, auth=DOMO_ALEXA_AUTH)
+        if resp.status_code == 200:
+            return resp.json()
+        else:
+            raise ValueError('code: %s' % resp.status_code)
+    finally:
+        log.info('domo call in %.3f sec' % (default_timer()-t))
+
+
+@ask.intent("SwitchIntent")
+def toggle_switch(OnOff):
+
+    did = context.System.device.get('deviceId')
+    room = ALEXA_DEVICE2ROOM.get(did)
+    if room is None:
+        return statement('Sorry, Ich weiss nicht wo du bist')
+
+    log.info('alexa: room %s switch: %s' % (room, OnOff))
+
+    assert OnOff in ON_OFF_SLOT
+    switchcmd = ON_OFF_SLOT[OnOff]
+
+    domo_idx = ROOM2POWER_DOMO_IDX[room]
+
+    log.info('domoticz: device %s switch: %s' % (domo_idx, switchcmd))
+
+    domo_command(param='switchlight', idx=domo_idx, switchcmd=switchcmd)
+    return statement('Ich habe das Licht im %s %sgeschaltet.' % (room, OnOff))

+ 10 - 19
alexa/server.py → alexa/app/server.py

@@ -1,18 +1,20 @@
 # -*- coding: utf-8 -*-
-from __future__ import print_function, absolute_import, division
+from __future__ import print_function, absolute_import, division, unicode_literals
 
-from flask import Flask
-from flask_ask import Ask, statement, question, session
+import logging
 import json
 import time
 from random import choice
+from timeit import default_timer
 
-app = Flask(__name__)
-ask = Ask(app, "/ameise")
+from flask_ask import statement, question, session, context
+from utils import get_alexa_location
 
-# the Links:
-# Config: https://developer.amazon.com/edw/home.html#/skills
-# Docs: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/supported-phrases-to-begin-a-conversation
+from ameise import app, ask, log
+
+# Intents
+import domo
+import chef
 
 WELCOME = [
     'Hast du einen Wunsch?',
@@ -42,17 +44,6 @@ def start_skill():
     print('Welcome ...')
     return question(choice(WELCOME)).reprompt(choice(REPROMPTS))
 
-@ask.intent("ChefIntent")
-def declare_chef():
-    names = ['Lilith', 'Elise', 'Lars', 'Annelie', 'Mama', 'Papa',
-            'Christine', 'Dirk', 'Lillutschka', 'Larsi', 'Liselchen', 'Annelutschka',
-            'Annelie Rothe', 'Lilith Rothe', 'Christine Rothe', 'Lars Rothe', 'Elise Rothe',
-            'die kleine Annelie', 'der schnelle Lars', 'die schlaue Elise', 'die intelligente Lilith']
-    chefs = ['Chef', 'Oberchef', 'Boss', 'Bestimmer', 'Meister',
-            'Leiter', 'Direktor', u'Anführer', 'Oberboss', u'König']
-    s = ('%s ist heute der %s, aber morgen ist %s dran!' %
-            (choice(names), choice(chefs), choice(names)))
-    return statement(s.encode('utf-8'))
 
 @ask.intent("LeaveIntent")
 def no_intent():

+ 13 - 0
alexa/app/utils.py

@@ -0,0 +1,13 @@
+
+import requests
+from flask_ask import Ask, statement, context
+
+def get_alexa_location():
+    URL =  "https://api.amazonalexa.com/v1/devices/{}/settings" \
+           "/address".format(context.System.device.deviceId)
+    TOKEN =  context.System.user.permissions.consentToken
+    HEADER = {'Accept': 'application/json',
+             'Authorization': 'Bearer {}'.format(TOKEN)}
+    r = requests.get(URL, headers=HEADER)
+    if r.status_code == 200:
+        return(r.json())

+ 6 - 1
alexa/readme.md

@@ -10,5 +10,10 @@ Ameisenhaufen
 +++++++++++++
 * Application Id: amzn1.ask.skill.0d944823-e51c-47a3-bddb-5043d6d9f3eb
 * connected to https://alexa.cere.duckdns.org/ameise
-* build logic in: https://developer.amazon.com/alexacreator/amzn1.ask.skill.0d944823-e51c-47a3-bddb-5043d6d9f3eb/development/de_DE
+
+* build logic in:   https://developer.amazon.com/alexacreator/amzn1.ask.skill.0d944823-e51c-47a3-bddb-5043d6d9f3eb/development/de_DE
+ * probably only via: https://developer.amazon.com/edw/home.html#/skill/amzn1.ask.skill.0d944823-e51c-47a3-bddb-5043d6d9f3eb/de_DE/info
+ * Do not forget to "Build Model" after adding utterances
+
 * docs: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/supported-phrases-to-begin-a-conversation
+ * or newer english: https://developer.amazon.com/designing-for-voice/

+ 3 - 1
services.yml

@@ -33,7 +33,7 @@ domoticz:
     volumes:
       - /etc/localtime:/etc/localtime
       - /mnt/ssdext/data/domoticz/domoticz.db:/root/domoticz/domoticz.db
-    #ports: 8080:8080
+    # ports: 8080:8080
     devices: /dev/ttyUSB0
 
 netdata:
@@ -166,6 +166,8 @@ alexa: # https://alexa.amazon.de
   host: himbeere
   docker:
     build: alexa
+    env:
+      DOMO_ALEXA_PW: ibm92buVQ12nhipkP4fg
 
 matrix: # interface with RGB LED-Matrix
   #~ fqdn: alexa.cere.duckdns.org