Ankündigung

Einklappen
Keine Ankündigung bisher.

Umfrage: Amazon Echo

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    #16
    Zitat von heckmannju Beitrag anzeigen

    Das hab ich ihm auch schon versucht klar zu machen.
    Also ich möchte an dieser Stelle mal kurz sagen, dass ich es super finde, dass es noch immer Benutzer gibt, die ein solches Sicherheitsbewusstsein haben. Wenn es mehr wie euch gäbe, dann wäre mein Job als IT Security Consultant um einiges einfacher. Tagtäglich bete ich hoch und runter, dass man vorsichtig sein muss, wenn es um IT geht. Bei allen unseren Kunden, wie große Automobilhersteller und Versicherungen im Raum Baden-Württemberg und Bayern.

    Ich will hier natürlich auch niemanden zwingen an etwas teilzuhaben, mit dem er sich nicht wohl fühlt. Es gibt Menschen, die mögen zum Beispiel einfach kein WLAN. Wegen der Strahlung. Ich habe daheim 2 Access Points. Einen im OG und einen im EG. Gibt ne bessere Funkabdeckung.

    Eines ist allerdings sicher. Wir reden hier nicht davon, dass das Plugin via FritzBox oder vergleichbarer Consumer Hardware einfach nackt ins Internet gestellt wird mittels Portforwarding oder NAT. Ich mein, ich bin ja nicht verrückt. Was für ein Mensch wäre ich, wenn ich die IT Sicherheit so leichtfertig außer Acht lasse.

    Was mir vorschwebt ist, dass das Plugin die Anfrage sehr wohl nur intern im LAN stellt. Einzig die JSON Datei mit den Anweisungen, was zu tun ist kommt von außen. Und das lässt sich auch nicht verhindern. Ansonsten würde der Service einfach nicht funktionieren. Dass man dazu am besten nicht einfach ein Portforwarding macht ist klar. Sonst könnte ja jeder als Angriffsvektor einfach eine JSON Datei an meinen Service schicken und dann meine Lampen und Jalousien bedienen, was im übrigen noch nicht mal so arg schlimm wäre. Zumindest nicht so schlimm, wie wenn mir Blueprints für die neue E-Klasse gestohlen würden.

    Fakt ist, dass ich tagtäglich große Firmen an Cloud Dienste ankopple. Damit verdien ich meine Brötchen. Ich würde also bescheiden behaupten, dass ich ein wenig Ahnung davon habe, was man macht und was nicht. Auch wenn manche Mitglieder hier sich das vielleicht nicht vorstellen können, dass man einen Cloud Service nutzen kann ohne, dass man sein Netzwerk nackt ins Internet stellen muss.

    Kommentar


      #17
      Hallo,
      also tendenziell habe ich Interesse und bin auch nicht ganz so skeptisch was die Security diesbezüglich angeht. Habe aber noch kein "Echo" und bin auch leider kein Entwickler:-(
      Bezüglich der SH-Umgebung bin ich auch noch auf der alten Version (weil stabil und UsZU funktioniert) unterwegs.

      Gruß Sascha

      Kommentar


        #18
        Okay. Jetzt haben wir ja immerhin schon 30 Stimmen. Sehr schön. Können denn vielleicht jene die sich für so ein Plugin interessieren mal sagen, ob sie vielleicht mithelfen können/wollen? Dann kann ich abschätzen, ob das Vorhaben was werden kann. Also rein vom KnowHow werde ich das wohl nicht vollständig stemmen können.

        Kommentar


          #19
          Nur um mal kurz hier den Gedankenstand festzuhalten. Ich bin glaube ich nur wenig von der Lösung entfernt. Das Alexa Skill kit kann ja 2 Typen von Skills bedienen. Einen Custom Skill und einen Smarthome Skill. Smarthome Skill? Klingt gut. Blöderweise sind die Möglichkeiten, was ich in meinem Haus dann steuern kann stark beschränkt, da Amazon hier das Sprachschema schon vorgibt, was der Programmierer nicht beeinflussen kann. Außerdem kann die Callback Funktion nur in der Amazon Cloud ausgeführt werden. Schlecht.

          Aber es gibt ja noch den Custom Skill. Hier können Utterances (Sprachschemen) selbst erstellt werden. Das heißt man legt also für jeden Endverbraucher Sprachmuster an. Zum Beispiel: "Alexa, schalte in {Raum} die {Lichttyp} {Zustand}" -> "Alexa schalte {im Büro} die {Spots} {an}". Soweit so gut. Raus kommt ein JSON, dass an meinen Service übermittelt wird. Bis hier hin traue ich mir zu ein Plugin in Python zu schreiben, was mit einem Amazon-API-Key identifiziert, ob die Anfrage auch wirklich von MEINER Alexa kommt und dann entsprechend das Licht schaltet. Problem hierbei ist nur, dass ich in dem Skill dann die Räume, die Lichttypen und auch die Zustände vorgeben muss.

          Ich hatte mir eher vorgestellt, dass sich die Möglichkeiten an Räume, Lichttypen/Jalousien/etc.. und Zustände daraus ergibt, was jemand in seine items.conf einträgt. So dass Amazon im JSON zumbeispiel einen Raum als wildcard weitergibt, egal ob er festgelegt wurde oder nicht und dann die items.conf nach diesem Objekt geparsed wird.

          Gibt es einen Treffer wird geschaltet, gibt es keinen gibt der Lautsprecher eine Rückmeldung, dass das Objekt nicht gefunden wurde.

          Vielleicht stehe ich auf dem Schlauch, oder ich erkenne es richtig und die Umsetzung wird nicht so leicht und komfortabel möglich sein, wie ich dachte. Wenn also jemand der von Programmieren eine Ahnung hat und sich mit dem Thema beschäftigt hat einen Tipp hat (ganz schön viele "hats") dann immer her damit. Ich wäre echt dankbar.

          Kommentar


            #20
            Wo siehst du eigentlich den Vorteil von dem Amazon Alexa zur Lösung mit dem Speech Plugin?

            Kommentar


              #21
              Ich kenne das Speech Plugin nicht. Ich kann also keinen direkten Vergleich anstellen. Aber wenn ich das richtig verstanden habe muss ich das Speech Plugin auf einem Endgerät mit Mikrofon und Lautsprecher installieren? Raspberry Pi? Das heißt ich habe ein System, das ich pflegen muss. Updates und Laufzeit muss gesichert werden. Außerdem muss ich das initial installieren. Das wollte ich mir sparen.

              Es gibt darüber hinaus weitere nützliche Funktionen von Amazon Echo, die ich abseits des SmartHomes nutzen möchte. Spotify zum Beispiel. Für mich hat sich die Wahl herausgestellt zwischen einer Sonos Play:1 und einem Amazon Echo. Soundqualität ist vergleichbar in meinem Ermessen und aufgrund der Zusatzfunktionen des Echos habe ich mich dafür entschieden.

              Aber wenn du möchtest kannst du mir gerne eine Kurzzusammenfassung des Speech Plugins geben, dann kann ich vielleicht Teile davon recyclen und für das Alexa Plugin nutzen.

              Kommentar


                #22
                Moin Patrick,

                Schau dir das Speech Plugin mal an. Da siehst du eine mögliche Lösung für das Problem. Allerdings wird sie dir vermutlich nicht gefallen, weil die Vorgabe, was man sagen muss recht start ist.
                Das Plugin benötigt allerdings keinen RasPi, sondern ein Handy mit Tasker. Dieses übernimmt die Spracherkennung und sendet das Gesagte an das Plugin.

                Was wir (ich kann Python, tue mich aber noch mit dem Programmieren von Plugins schwer) ja nutzen wollen, ist auch die Kontext-Fähigkeit (bitte schalte das Licht im Wohnzimmer an. Und erhöhe auch die Temperatur um 1°) von Alexa, sowie die Fähigkeit, dass "Kinderzimmer" und "im Zimmer von Kevin" oder "Wohnbereich" und "Couch" das gleiche sein kann.

                ​​​​​​Eine Lösung dafür sehe ich so jetzt auch erstmal nicht. Ich denke schon, dass man letztlich Informationen an den "Alexa-Part" des Plugin geben muss; Es wäre gut, wenn das Plugin das machen könnte, z.B. indem man den zu steuernden Items einen Parameter "Alexa" sowie weitere Parameter "Alexa-Synonyme" gibt. Diese Informationen muss das Plugin dann bei der Installation oder bei Updates der Items zu Amazon hochladen.

                Gruß,
                Hendrik

                Kommentar


                  #23
                  Moin Hendrik,

                  du hast recht. Ein Verkettung von Befehlen wäre sicherlich auch cool. Ich für meinen Teil würde mich durchaus zufrieden geben, wenn ich einzelne Befehle hintereinander geben könnte. Im Zweifel hat man ja auch noch die Szenen und kann dadurch eine Verkettung von Befehlen auf nur einen Befehl einstellen.

                  Interessant wäre es, wenn man aus dem Erzeugen einer item.conf kontextsensitiv einen Alexa Sprachsatz erzeugen könnte. Blöderweise zielt Amazon darauf leider nicht ab. Das wird so nicht funktionieren. Die Eingabe von Sprachschemen und auch mögliche Auswahlen scheint bei Amazon momentan Handarbeit zu sein. Der Amerikaner kann einen sogenannten Slot-Type auswählen, der sich LITERAL nennt. Dabei versucht die Sprachengine nach einem Schlüsselteilsatz das Gesagte in ein Objekt zu verwandeln.

                  Für Deutschland allerdings scheint die Entwicklung durch Amazon noch nicht so fortgeschritten, dass wir es uns zu Nutzen machen könnten. Das bedeutet, wenn du in deinem Haus 10 unterschiedliche Räume hast und 5 unterschiedliche Lampentypen usw.. dann muss man das im Developer Portal von Hand in die passend benamste Liste eintragen.

                  Was man sich vorstellen könnte wäre ein bisschen Python Magie, die es Benutzern mit wenig Programmiererfahrung möglich macht durch die Ausgabe einer Datei den Inhalt davon nur bei Amazon zu Pasten. Fraglich ist, ob sich der Aufwand lohnt. Tja und was machen wir bei Updates. Zwar bleiben die Items ja relativ statisch. Aber wenn man sie je anpasst, muss auch der gesamte Quelltext und alle Parameter bei Amazon angepasst werden. Ich sage mal, so hab ich mir das Plugin natürlich nicht vorgestellt.

                  Es bleibt eventuell noch die Smart Home API für Alexa, die momentan aber nur Lichet an und aus machen kann und dimmen. Außerdem kann sie Thermostate bedienen. Sollte Amazon also diese API ausbauen ist es einfacher, weil dafür nur eine Schnittstelle bei Amazon geschrieben werden muss, die die Anfrage an unser Plugin weiterschickt.

                  Ich schaue mir mal das Speech Plugin an und schaue, was davon ich verwenden kann für den Listener und den Part, der das Item nachher schaltet. Danke.

                  Kommentar


                    #24
                    Hallo Patrick,

                    ein überaus spannendes Thema, finde ich.
                    Bei mir läuft das speech-plugin, es braucht aber wie gesagt einen Androiden, auf dem Tasker und AutoVoice läuft. Und das beißt sich mit anderen Anwendungen, die ich benutze. Deshalb wäre ich auch an einer Alternative interessiert.

                    Eine item.conf zu parsen und zu einem Sprachsatz zu kommen, greift meines Erachtens zu kurz: Die Items sind ja nicht doppelt benamt, heißt, dass Kinderzimmer auch Kevins Zimmer heißen kann, oder statt Licht auch Beleuchtung oder Lampen verwendet werden kann. Aber das weiß die items.conf nicht.
                    Bei speech übernimmt das die conf-Datei, in der man selbst die Redundanzen pflegt.
                    So sieht's aus:
                    varRaum = [
                    ['EG.Wohnen', ['wohnzimmer', 'stube', 'wohnen', 'wohnbereich']],
                    ['EG.Essen', ['küchenbereich', 'kochbereich', 'küche', 'kochen']],
                    ['EG.Duschen', ['bad', 'badezimmer', 'dusche', 'WC']],
                    ['EG.Schlafen', ['schlafzimmer', 'schlafen', 'eltern']],
                    ['EG.Essen', ['esszimmer', 'essen', 'essbereich']],
                    ['EG.Oekonomie', ['aussen', 'hof', 'vorplatz', 'draußen']] ...
                    Was vom Androiden kommt, ist nur ein Http-request mit der erkannten Wortkombination. Z.B.
                    Licht im Wohnzimmer ausschalten
                    oder als request:
                    http://192.168.2.5:2788?Licht%20im%2...%20ausschalten
                    es könnte auch
                    Beleuchtung Wohnen aus
                    sein, geparst wird von speech beides zu:
                    EG.Wohnen. Sprachbeleuchtung.Schalten 0
                    Nun will Alexa ja wesentlich mehr: Da soll der Webservice bitteschön die Alexa ID und einen Timestamp auswerten, aber grundsätzlich denke ich,man könnte Beides verheiraten.

                    Nun aber noch ein Punkt: Google Home wäre mir eigentlich lieber. Ganz einfach deshalb, weil ich mit Google mehr mache als mit Amazon. Da könnte man z.B. den Kalender per nativer API füllen oder auslesen etc.
                    Allerdings habe ich noch Nichts gefunden, mit dem sich aus Google-Home direkt ein HTML-Request entlocken ließe. Es gibt da die Möglichkeit über IFTTT und dem Service Maker, dann kommen Schaltbefehle aber wieder aus dem großen Internet und wollen sicher nach drinnen gegeben werden. Darüber hinaus kam aus Maker noch kein Request bei mir an.

                    Beste Grüße,
                    Jürgen

                    Kommentar


                      #25
                      Hallo Jürgen,

                      du hast vollkommen recht, das das reine Aufführen von einem Wort pro Raum nicht dem natürlichen Sprachgebrauch entspricht. Das macht man bei Amazon mit den sogenannten Utterances in Kombination mit den Slots. Und genau das ist hier eben die riesige Handarbeit. Ich bin noch nicht davon überzeugt, dass sich Alexa im jetzigen Entwicklungsstand von Amazon komfortabel in SH.py integrieren lässt. Noch fehlt mir die zündende Idee.

                      Ich will hier mal schnell zusammenfassen wie das mit Alexa funktioniert bei Amazon. Vielleicht hat ja noch jemand ne Idee, wie man das gut lösen kann.

                      Also zuerst legt man mal fest, was man sagen muss, damit der Skill überhaupt angesprochen wird. In meinem Beispiel ist das "das haus". Der sogenannte Invocation Name. Nach dem Motto: "Alexa, frag das Haus nach Spots im Büro an". Das war so halbwegs das natürlichste, was ich mit den Möglichkeiten, die Amazon liefert formen konnte. Siehe dazu auch Bild 1.

                      Dann muss man ein Intent Schema erstellen. Also welche unterschiedlichen Anfragemöglichkeiten oder auch Aktionen möchte man dem Skill verpassen. In meinem beispiel ist es:

                      - Licht schalten
                      - Licht dimmen
                      - Jalousie bewegen
                      - Jalousie stoppen
                      - Jalousieposition vorgeben
                      - Lamellenwinkel bestimmen
                      - Strom schalten
                      - Türe öffnen

                      Im Codebeispiel sieht man, wie diese Intents als JSON Format verfasst werden. Jeder Intent hat die Möglichkeit einen oder mehrere Slots (Variablen) zu haben. Für den Type habe ich immer "Custom" gewählt und damit eine eigene Liste von Möglichen Eingaben erstellt.

                      Code:
                      {
                        "intents": [
                          {
                            "intent": "SwitchLight",
                            "slots": [
                                {
                                "name": "RoomName",
                                "type": "List_Of_Rooms"
                                 },
                              {
                                "name": "LightName",
                                "type": "List_Of_Lights"
                              },
                              {
                                "name": "SwitchState",
                                "type": "SwitchState"
                              }
                            ]
                          },{
                            "intent": "DimLight",
                            "slots": [
                                {
                                "name": "RoomName",
                                "type": "List_Of_Rooms"
                                 },
                              {
                                "name": "LightName",
                                "type": "List_Of_Lights"
                              },
                              {
                                "name": "Brightness",
                                "type": "AMAZON.NUMBER"
                              }
                            ]
                          },
                          {
                            "intent": "MoveShutter",
                            "slots": [
                                {
                                "name": "RoomName",
                                "type": "List_Of_Rooms"
                                 },
                              {
                                "name": "ShutterName",
                                "type": "List_Of_Shutter"
                              },
                              {
                                "name": "Direction",
                                "type": "Direction"
                              }
                            ]
                          },
                          {
                            "intent": "StopShutter",
                            "slots": [
                                {
                                "name": "RoomName",
                                "type": "List_Of_Rooms"
                                 },
                              {
                                "name": "ShutterName",
                                "type": "List_Of_Shutter"
                              }
                            ]
                          },
                          {
                            "intent": "ShutterPosition",
                            "slots": [
                                {
                                "name": "RoomName",
                                "type": "List_Of_Rooms"
                                 },
                              {
                                "name": "ShutterName",
                                "type": "List_Of_Shutter"
                              },
                              {
                                "name": "Position",
                                "type": "AMAZON.NUMBER"
                              }
                            ]
                          },
                          {
                            "intent": "BlindAngle",
                            "slots": [
                                {
                                "name": "RoomName",
                                "type": "List_Of_Rooms"
                                 },
                              {
                                "name": "ShutterName",
                                "type": "List_Of_Shutter"
                              },
                              {
                                "name": "Angle",
                                "type": "AMAZON.NUMBER"
                              }
                            ]
                          },
                          {
                            "intent": "SwitchPower",
                            "slots": [
                                {
                                "name": "RoomName",
                                "type": "List_Of_Rooms"
                                 },
                              {
                                "name": "PowerSocket",
                                "type": "List_Of_PowerSockets"
                              },
                              {
                                "name": "SwitchState",
                                "type": "SwitchState"
                              }
                            ]
                          },
                          {
                            "intent": "OpenDoor"
                          }
                      
                        ]
                      }
                      Um zu sehen, welche Möglichkeiten ich in meiner Liste vorgebe schaut euch bitte Bild 2 an.

                      Spätestens jetzt sollte klar werden, dass es für den späteren Anwender sehr schwer wird das komfortabel zu pflegen.
                      So nun muss man noch einem geschlossenen Satz einem Intent zuordnen. Das macht man über die Utterances

                      Code:
                      SwitchLight {LightName} im {RoomName} {SwitchState}
                      SwitchLight {LightName} in {RoomName} {SwitchState}
                      SwitchLight {LightName} auf {RoomName} {SwitchState}
                      SwitchLight {LightName} {RoomName} {SwitchState}
                      DimLight Dimme {LightName} im {RoomName} auf {Brightness} Prozent
                      DimLight Dimme {LightName} in {RoomName} auf {Brightness} Prozent
                      DimLight Dimme {LightName} {RoomName} auf {Brightness} Prozent
                      DimLight Dimme {LightName} im {RoomName} auf {Brightness}
                      DimLight Dimme {LightName} in {RoomName} auf {Brightness}
                      DimLight Dimme {LightName} {RoomName} auf {Brightness}
                      DimLight Dimme {LightName} im {RoomName} {Brightness} Prozent
                      DimLight Dimme {LightName} in {RoomName} {Brightness} Prozent
                      DimLight Dimme {LightName} {RoomName} {Brightness} Prozent
                      DimLight Dimme {LightName} im {RoomName} {Brightness}
                      DimLight Dimme {LightName} in {RoomName} {Brightness}
                      DimLight Dimme {LightName} {RoomName} {Brightness}
                      MoveShutter {ShutterName} im {RoomName} {Direction}
                      MoveShutter {ShutterName} in {RoomName} {Direction}
                      MoveShutter {ShutterName} {RoomName} {Direction}
                      StopShutter {ShutterName} im {RoomName} Stop
                      StopShutter {ShutterName} in {RoomName} Stop
                      StopShutter {ShutterName} {RoomName} Stop
                      StopShutter {ShutterName} im {RoomName} Halt
                      StopShutter {ShutterName} in {RoomName} Halt
                      StopShutter {ShutterName} {RoomName} Halt
                      ShutterPosition {ShutterName} im {RoomName} {Position} Prozent
                      ShutterPosition {ShutterName} in {RoomName} {Position} Prozent
                      ShutterPosition {ShutterName} {RoomName} {Position} Prozent
                      ShutterPosition {ShutterName} im {RoomName} auf {Position} Prozent
                      ShutterPosition {ShutterName} in {RoomName} auf {Position} Prozent
                      ShutterPosition {ShutterName} {RoomName} auf {Position} Prozent
                      BlindAngle {ShutterName} Lamellen im {RoomName} {Angle} Grad
                      BlindAngle {ShutterName} Lamellen in {RoomName} {Angle} Grad
                      BlindAngle {ShutterName} Lamellen {RoomName} {Angle} Grad
                      BlindAngle {ShutterName} Lamellen im {RoomName} auf {Angle} Grad
                      BlindAngle {ShutterName} Lamellen in {RoomName} auf {Angle} Grad
                      BlindAngle {ShutterName} Lamellen {RoomName} auf {Angle} Grad
                      SwitchPower Strom {PowerSocket} im {RoomName} {SwitchState}
                      SwitchPower Strom {PowerSocket} in {RoomName} {SwitchState}
                      SwitchPower Strom {PowerSocket} auf {RoomName} {SwitchState}
                      SwitchPower Strom {PowerSocket} {RoomName} {SwitchState}
                      OpenDoor Öffne Türe
                      OpenDoor Öffne Haustüre
                      OpenDoor Türe auf
                      OpenDoor Haustüre auf
                      OpenDoor Türe öffnen
                      OpenDoor Haustüre öffnen
                      Zuerst wird die Funktion genannt und dann der Beispielsatz mit Platzhaltern für die Slots.

                      Nun kann ich das testen via Konsole indem ich eine Sprachvorgabe eingebe und mir die Konsole liefert, was sie der Funktion (dem Plugin) senden würde:

                      "Spots im Büro an"

                      Code:
                      {
                        "session": {
                          "sessionId": "geschwärzt",
                          "application": {
                            "applicationId": "geschwärzt"
                          },
                          "attributes": {},
                          "user": {
                            "userId": "geschwärzt"
                          },
                          "new": true
                        },
                        "request": {
                          "type": "IntentRequest",
                          "requestId": "geschwärzt",
                          "locale": "de-DE",
                          "timestamp": "2016-11-08T13:35:10Z",
                          "intent": {
                            "name": "SwitchLight",
                            "slots": {
                              "SwitchState": {
                                "name": "SwitchState",
                                "value": "an"
                              },
                              "RoomName": {
                                "name": "RoomName",
                                "value": "Buero"
                              },
                              "LightName": {
                                "name": "LightName",
                                "value": "Spots"
                              }
                            }
                          }
                        },
                        "version": "1.0"
                      }
                      Hier wird also durch die Utterance erkannt, dass ich SwitchLight machen will mit dem SwitchState an, RoomName Buero, LightName Spots.

                      Das war der Teil der Sprachgestaltung. Bis hier hin muss man sehr viel Arbeit reinstecken. Aber ohne Funktion (node.js) dahinter ist die Spracherkennung nutzlos.

                      Daher habe ich momentan noch bei Amazon eine sogenannte Lambda Funktion, geschrieben in Node.js hinterlegt, die die eigentliche Aktion macht. Diese JSON Anfrage von oben würde ich zukünftig gerne Richtung SH.py senden. Hierbei soll SH.py folgende Funktionalität übernehmen:

                      Code:
                      const https = require('https');
                      
                      exports.handler = (event, context) => {
                      
                          try {
                      
                              if (event.session.new) {
                          // New Session
                          console.log("NEW SESSION");
                          }
                      
                          switch (event.request.type) {
                      
                              case "LaunchRequest":
                              // Launch Request
                              console.log(`LAUNCH REQUEST`);
                              context.succeed(
                                generateResponse(
                                  buildSpeechletResponse("Willkommen",true),
                                  {}
                                )
                              );
                              break;
                      
                              case "IntentRequest":
                              // > Intent Request
                              console.log('INTENT REQUEST');
                      
                              switch (event.request.intent.name) {
                      
                                case "SwitchLight":              
                      
                                    var build = buildPathLight(event.request.intent.slots.RoomName.value, event.request.intent.slots.LightName.value, event.request.intent.slots.SwitchState.value);
                                    var path = build[0];              
                                    var response = build[1];    
                      
                                    var options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  var req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                               case "DimLight":              
                      
                                    build = buildPathDimLight(event.request.intent.slots.RoomName.value, event.request.intent.slots.LightName.value, event.request.intent.slots.Brightness.value);
                                    path = build[0];              
                                    response = build[1];    
                      
                                    options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                                case "MoveShutter":
                      
                                      build = buildPathShutter(event.request.intent.slots.RoomName.value, event.request.intent.slots.ShutterName.value, event.request.intent.slots.Direction.value);
                                      path = build[0];
                                      response = build[1];
                      
                                      options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                                case "StopShutter":              
                      
                                    build = buildPathShutter(event.request.intent.slots.RoomName.value, event.request.intent.slots.ShutterName.value, "stop");
                                    path = build[0];              
                                    response = build[1];    
                      
                                    options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                                case "ShutterPosition":              
                      
                                    build = buildPathPosition(event.request.intent.slots.RoomName.value, event.request.intent.slots.ShutterName.value, event.request.intent.slots.Position.value);
                                    path = build[0];              
                                    response = build[1];    
                      
                                    options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                              case "BlindAngle":              
                      
                                    build = buildBlindAngle(event.request.intent.slots.RoomName.value, event.request.intent.slots.ShutterName.value, event.request.intent.slots.Angle.value);
                                    path = build[0];              
                                    response = build[1];    
                      
                                    options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                              case "SwitchPower":              
                      
                                    build = buildPowerPath(event.request.intent.slots.RoomName.value, event.request.intent.slots.PowerSocket.value, event.request.intent.slots.SwitchState.value);
                                    path = build[0];              
                                    response = build[1];    
                      
                                    options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                              case "OpenDoor":              
                      
                                    path = "/item|EG.Eingang.Summer|1";
                                    response = "Die Haustüre wurde geöffnet";
                      
                                    options = {
                                      hostname: 'geschwärzt',
                                      port: 443,
                                      path: path,
                                      method: 'GET',
                                      headers: {
                                          Authorization: 'Basic ' + new Buffer('geschwärzt').toString('base64')
                                      }
                                    };
                      
                                  req = https.request(options, (res) => {
                                      console.log('statusCode: ', res.statusCode);
                                      console.log('headers: ', res.headers);
                      
                                  res.on('data', (d) => {
                                      process.stdout.write(d);
                                  });
                                  context.succeed(
                                      generateResponse(
                                       buildSpeechletResponse(response,true),
                                       {}
                                      )
                                    );
                              });
                              req.end();
                      
                              req.on('error', (e) => {
                                  console.error(e);
                              });
                              console.log(path);
                                break;
                      
                           default:
                           context.fail('INVALID REQUEST TYPE: ${event.request.type}');
                      
                      
                              } //Ende switch intent request. alle intent request arten vor dieser klammer als case
                            break; //break switch intent reuest
                      
                            case "SessionEndedRequest":
                            // > Session Ended Request
                            console.log('SESSION ENDED REQUEST');
                            break;
                      
                            default:
                            context.fail('INVALID REQUEST TYPE: ${event.request.type}');
                          }
                      
                       } catch(error) { context.fail(`Exception: ${error}`) }
                      
                      };
                      
                      // Helpers
                      buildSpeechletResponse = (outputText, shouldEndSession) => {
                      
                        return {
                          outputSpeech: {
                            type: "PlainText",
                            text: outputText
                          },
                          shouldEndSession: shouldEndSession
                        };
                      
                      };
                      
                      generateResponse = (speechletResponse, sessionAttributes) => {
                      
                        return {
                          version: "1.0",
                          sessionAttributes: sessionAttributes,
                          response: speechletResponse
                        };
                      
                      };
                      
                      // Build Functions
                      
                      function buildPathLight(raum, licht, state) {
                      
                          var State = state;
                      
                          var Licht = rewriteLight(licht);
                      
                          var BuildRaum = rewriteRoom(raum);
                      
                          var Geschoss = BuildRaum[0];    
                      
                          var Raum = BuildRaum[1];
                      
                          switch (State) {
                      
                                      case "an":
                                           var path = '/item|' + Geschoss + '.' + Raum + '.' + Licht + '.Schalten|1';
                                           var response = Licht + " im " + raum + " wurde eingeschaltet";
                                      break;
                      
                                    case "aus":
                                           path = '/item|' + Geschoss + '.' + Raum + '.' + Licht + '.Schalten|0';
                                           response = Licht + " im " + raum + " wurde ausgeschaltet";
                                    break;  
                      
                                    }
                      
                          return [path, response];
                      }
                      
                      function buildPathDimLight(raum, licht, helligkeit) {
                      
                          var Helligkeit = helligkeit * 255 / 100;
                      
                          var Licht = rewriteLight(licht);
                      
                          var BuildRaum = rewriteRoom(raum);
                      
                          var Geschoss = BuildRaum[0];    
                      
                          var Raum = BuildRaum[1];
                      
                          var path = '/item|' + Geschoss + '.' + Raum + '.' + Licht + '.Dimmen|' + Helligkeit;
                          var response = Licht + " im " + raum + " wurde auf " + helligkeit + ' Prozent gedimmt';
                      
                          return [path, response];
                      }
                      
                      function buildPowerPath(raum, steckdose, state) {
                      
                          var State = state;
                      
                          var Steckdose = rewriteSteckdose(steckdose);
                      
                          var BuildRaum = rewriteRoom(raum);
                      
                          var Geschoss = BuildRaum[0];    
                      
                          var Raum = BuildRaum[1];
                      
                          switch (State) {
                      
                                      case "an":
                                           var path = '/item|' + Geschoss + '.' + Raum + '.' + Steckdose + '|1';
                                           var response = "Steckdose " + steckdose + " im " + raum + " wurde eingeschaltet";
                                      break;
                      
                                    case "aus":
                                           path = '/item|' + Geschoss + '.' + Raum + '.' + Steckdose + '|0';
                                           response = "Steckdose " + steckdose + " im " + raum + " wurde ausgeschaltet";
                                    break;  
                      
                                    }
                      
                          return [path, response];
                      }
                      
                      function buildPathShutter(raum, shutter, state) {
                      
                          var State = state;
                      
                          var Shutter = rewriteShutter(shutter);
                      
                          var BuildRaum = rewriteRoom(raum);
                      
                          var Geschoss = BuildRaum[0];
                      
                          var Raum = BuildRaum[1];
                      
                      
                          switch (State) {
                      
                                      case "auf":
                                           var path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Fahren|0';
                                           var response = Shutter + " im " + raum + " wird hoch gefahren";
                                      break;
                      
                                      case "hoch":
                                           path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Fahren|0';
                                           response = Shutter + " im " + raum + " wird hoch gefahren";
                                      break;
                      
                                      case "zu":
                                           path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Fahren|1';
                                           response = Shutter + " im " + raum + " wird runter gefahren";
                                      break;
                      
                                      case "ab":
                                           path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Fahren|1';
                                           response = Shutter + " im " + raum + " wird runter gefahren";
                                      break;
                      
                                      case "runter":
                                           path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Fahren|1';
                                           response = Shutter + " im " + raum + " wird runter gefahren";
                                      break;
                      
                                      case "stop":
                                          path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Stop|1';
                                          response = Shutter + " im " + raum + " wurde gestoppt";
                                      break;
                      
                                    }
                      
                          return [path, response];
                      }
                      
                      function buildBlindAngle(raum, shutter, winkel) {
                      
                          var Winkel = winkel * 255 / 360;
                      
                          var Shutter = rewriteShutter(shutter);
                      
                          var BuildRaum = rewriteRoom(raum);
                      
                          var Geschoss = BuildRaum[0];
                      
                          var Raum = BuildRaum[1];
                      
                          var path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Lamelle|' + Winkel;
                          var response = "Lamellen von " + Shutter + " im " + raum + " werden gekippt auf " + winkel + " Grad";
                      
                          return [path, response];              
                      }
                      
                      function buildPathPosition(raum, shutter, position) {
                      
                          var Position = position * 255 / 100;
                      
                          var Shutter = rewriteShutter(shutter);
                      
                          var BuildRaum = rewriteRoom(raum);
                      
                          var Geschoss = BuildRaum[0];
                      
                          var Raum = BuildRaum[1];
                      
                          var path = '/item|' + Geschoss + '.' + Raum + '.' + Shutter + '.Position|' + Position;
                          var response = Shutter + " im " + raum + " wird gefahren auf " + position + " Prozent";
                      
                          return [path, response];              
                      }
                      
                      // Rewrite Functions
                      
                      function rewriteRoom(raum) {
                          var Geschoss = "";
                      
                          var Raum = raum;
                          String(Raum);
                          Raum = Raum.charAt(0).toUpperCase() + Raum.slice(1);
                          Raum = Raum.replace(/ä/g,"ae").replace(/ö/g,"oe").replace(/ü/g,"ue").replace(/Ä/g,"Ae").replace(/Ö/g,"Oe").replace(/Ü/g,"Ue").replace(/ß/g,"ss");    
                      
                          switch (Raum) {    
                      
                                      case "Wohnzimmer":
                                          Geschoss = "EG";
                                          Raum = "Wohnzimmer";
                                          break;
                                      case "Esszimmer":
                                          Geschoss = "EG";
                                          Raum = "Esszimmer";
                                          break;
                                      case "Kueche":
                                          Geschoss = "EG";
                                          Raum = "Kueche";
                                          break;
                                      case "Eingang":
                                          Geschoss = "EG";
                                          Raum = "Eingang";
                                          break;
                                      case "WC":
                                          Geschoss = "EG";
                                          Raum = "WC";
                                          break;
                                      case "Speissekammer":
                                          Geschoss = "EG";
                                          Raum = "Speissekammer";
                                          break;
                                      case "Terasse":
                                          Geschoss = "EG";
                                          Raum = "Terasse";
                                          break;
                                      case "Schlafzimmer":
                                          Geschoss = "OG";
                                          Raum = "Schlafzimmer";
                                          break;
                                      case "Eltern":
                                          Geschoss = "OG";
                                          Raum = "Schlafzimmer";
                                          break;
                                      case "Ankleide":
                                          Geschoss = "OG";
                                          Raum = "Ankleide";
                                          break;
                                      case "Kind":
                                          Geschoss = "OG";
                                          Raum = "Kind";
                                          break;
                                      case "Kinderzimmer":                    
                                          Geschoss = "OG";
                                          Raum = "Kind";
                                          break;
                                      case "Buero":                    
                                          Geschoss = "OG";
                                          Raum = "Buero";
                                          break;
                                      case "Badezimmer":
                                          Geschoss = "OG";
                                          Raum = "Badezimmer";
                                          break;
                                      case "Bad":
                                          Geschoss = "OG";
                                          Raum = "Badezimmer";
                                          break;
                                      case "Flur":
                                          Geschoss = "OG";
                                          Raum = "Flur";
                                          break;
                                    }
                                    return [Geschoss, Raum];
                      }
                      
                      function rewriteShutter(shutter) {
                      
                          var Shutter = shutter;
                          String(Shutter);
                          Shutter = Shutter.charAt(0).toUpperCase() + Shutter.slice(1);
                          Shutter = Shutter.replace(/ä/g,"ae").replace(/ö/g,"oe").replace(/ü/g,"ue").replace(/Ä/g,"Ae").replace(/Ö/g,"Oe").replace(/Ü/g,"Ue").replace(/ß/g,"ss");
                      
                      
                          switch (Shutter) {
                              case "Jalousie":
                              Shutter = "Jalousie";
                              break;
                              case "Jalousie Kleines Festglas":
                              Shutter = "JalousieKLFG";
                              break;
                              case "Jalousie Grosses Festglas":
                              Shutter = "Jalousie";
                              break;
                              case "Jalousie Terassentuere":
                              Shutter = "JalousieTerasse";
                              break;
                              case "Jalousie Tuere":
                              Shutter = "JalousieTuer";
                              break;
                              case "Jalousie Tuer":
                              Shutter = "JalousieTuer";
                              break;
                              case "Kleine Jalousie":
                              Shutter = "JalousieKlein";
                              break;
                              case "Grosse Jalousie":
                              Shutter = "JalousieGross";
                              break;
                          }
                      
                          return Shutter;
                      }
                      
                      function rewriteLight(licht) {
                          var Licht = licht;
                          String(Licht);
                          Licht = Licht.charAt(0).toUpperCase() + Licht.slice(1);
                          Licht = Licht.replace(/ä/g,"ae").replace(/ö/g,"oe").replace(/ü/g,"ue").replace(/Ä/g,"Ae").replace(/Ö/g,"Oe").replace(/Ü/g,"Ue").replace(/ß/g,"ss");
                      
                          switch (Licht) {
                              case "Lampen Sued":
                              Licht = "LampenSued";
                              break;
                          }
                      
                          return Licht;
                      }
                      
                      function rewriteSteckdose(steckdose) {
                      
                          var Steckdose = steckdose;
                          String(Steckdose);
                          Steckdose = Steckdose.charAt(0).toUpperCase() + Steckdose.slice(1);
                          Steckdose = Steckdose.replace(/ä/g,"ae").replace(/ö/g,"oe").replace(/ü/g,"ue").replace(/Ä/g,"Ae").replace(/Ö/g,"Oe").replace(/Ü/g,"Ue").replace(/ß/g,"ss");
                      
                          switch (Steckdose) {
                              case "Caddi":
                              Steckdose = "Steckdose_Caddi";
                              break;
                              case "Patrick":
                              Steckdose = "Steckdose_Patrick";
                              break;
                              case "TV":
                              Steckdose = "Steckdose_TV";
                              break;
                              case "Sued":
                              Steckdose = "SteckdosenSued";
                              break;
                          }
                      
                          return Steckdose;
                      }
                      Und spätestens nachdem man nun hier gesehen hat wieviele rewrite und build Funktionen man implementieren muss, die genaustens auf die eigenen Items zugeschnitten sind sollte klar sein, dass das so nicht praktikabel ist. Für meine Infrastruktur funktioniert das super. Ich hab das so programmiert, dass das mit meinen Items funktioniert. Das kann aber jemand anderes nicht einfach so adaptieren.

                      Und genau deshalb wollte ich ein solches Schema am besten aus den Items heraus parsen und dann die notwendigen Intents, Slots und Utterances generieren lassen. So hätte wenigstens jeder halbwegs eine Chance das durchzuklicken bei Amazon.


                      Jetzt sind die gefragt, die in dem was ich bisher habe eine Chance sehen was cooles draus zu machen. Ich für meinen Teil stehe momentan etwas auf dem Schlauch. Sollte es Fragen zu dem Amazon Skills Kit geben dann her damit. Ich habe mich ziemlich damit beschäftigt und kann das vielleicht beantworten.

                      Danke und Grüße,
                      Patrick
                      You do not have permission to view this gallery.
                      This gallery has 2 photos.
                      Zuletzt geändert von patrickgoll; 08.11.2016, 14:54.

                      Kommentar


                        #26
                        Hallo Patrick,

                        ich habe leider keine Antworten auf Deine Fragen.

                        Aber selbst eine Detailfrage: Ich habe testweise eine Portweiterleitung (speech-port 2788) auf smarthome.py eingerichtet. Also genau das, was man am liebsten vermeiden möchte. Weiter vorn im Thread hattest Du geschrieben, dass Du Deinen Port abgesichert hast, ich hab's aber nicht im Detail verstanden.

                        Kannst Du es mir bitte erläutern?

                        Danke,
                        Jürgen

                        Kommentar


                          #27
                          Hallo Jürgen,

                          ich habe meinen Port mit einer Firewall aus dem Business Bereich abgesichert. Der Hersteller Sophos baut Firewalls, sogenannte Unified Threat Management Security Lösungen oder kurz UTM. Dabei handelt es sich um ein gehärtetes Linux System, dass jede Menge Proxy Produkte inbegriffen hat. Web Surfing wird so zum Beispiel durch einen Proxy gefiltert und auf Gefahren untersucht. Gleiches gilt für Mail.

                          Die Komponente der UTM, die ich genutzt habe, ist der sogenannte Reverse Proxy. Sophos nennt das consumer tauglich "Web Server Protection". Hierbei handelt es sich also um eine umgedrehte Proxy Verbindung. Nicht was von innen nach außen gesurft wird, sondern von außen nach innen wird auf Bedrohungen untersucht.

                          Im Klartext heißt das, dass Manipulationen durch Sicherheitslücken wie javascript Verwundbarkeiten erkannt und beseitigt werden. Darüber hinaus lässt sich dieser Zugriff dann noch mit Benutzername und Kennwort absichern, vorgelagert. Das bedeutet, dass vor dem eigentlichen Zugriff auch noch Benutzername und Kennwort eingegeben werden muss. Scheitert der "Angreifer" hier (und das tut er dafür gibt es kein Angriffsszenario als ausprobieren, und selbst da wird man gesperrt nach mehrmaliger falscher Eingabe und sogar per Email benachrichtigt) hat er keine Chance auf deinen offenen Port zuzugreifen.

                          Das ist so sicher zu sehen, wie ein natives VPN, was die UTM logischerweise auch bieten kann. Diese UTM ist für Heimanwender kostenlos zu beziehen im vollen Funktionsumfang und kann auf einer kleinen Hardware mit Intel basiertem Chip (Celeron J1900) installiert werden. Allerdings ist die Konfiguration von so etwas nicht gleichzusetzen mit einem Consumer Router wie einer FritzBox.

                          Es gibt auch weitere kostenlose Produkte, die gut und leichter sind. Der "Kassen"renner ist hier zum Beispiel pfSense, was sich fast so einfach wie eine Fritzbox konfiguriert und einen ähnlichen Funktionsumfang hat.

                          Letztlich bleibt einem aber auch noch sowas, wie ein Raspberry Pi, auf dem man genau das gleiche Paket installieren kann wie auf einer Sophos UTM, denn auch die kochen nur mit Wasser. Dann kann man diesen ReverseProxy (zwar auf der Kommandozeile, aber immerhin) genauso passend konfigurieren und mit einer Benutzerauthentifizierung belegen.

                          Das ist im großen und ganzen das, was ich hier empfehlen würde um so ein Szenario abzubilden. Sicher nicht ein Einsteiger Niveau, was IT Security angeht, aber immerhin machbar.

                          Sollte ich dir sonst noch weiterhelfen können, dann immer raus damit.

                          Grüße,
                          Patrick

                          Kommentar


                            #28
                            Moin Patrick,

                            tolle Beschreibung, wie Alexa funktioniert. Danke.
                            Ich denke, wir kommen nicht umhin einen Wortschatz zu definieren, denke aber, dass man das zentral machen kann.
                            Mein Gedanke wäre, dass man einen Wortschatz für das Plugin definiert -dieser kann ja bei Bedarf erweitert werden (ähnlich dem KNX-UF Icon-Set). Einzig Eigennamen würden außen vor beleiben.
                            Darauf müsste man entweder verzichten, oder diese selbst hinzufügen. Man könnte dafür ja Platzhalter lassen.

                            Übersehe ich etwas?

                            Gruß,
                            Hendrik

                            Kommentar


                              #29
                              Hallo Patrick,
                              danke für die ausführliche Antwort. Ich werde mal Google anschmeißen und schauen, wie man zu bezahlbaren Kosten zu einem Reverse-Proxy kommt.

                              Beste Grüße,
                              Jürgen

                              Kommentar


                                #30
                                Kennst du das?

                                http://www.fhemwiki.de/wiki/Alexa-Fhem

                                Kommentar

                                Lädt...
                                X