Dinge
This commit is contained in:
parent
6dbc675a8b
commit
fdb5abc125
10
Snips/Events/TextEvent.cs
Normal file
10
Snips/Events/TextEvent.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.Events {
|
||||
public class TextEvent : EventArgs { }
|
||||
|
||||
public class StringEvent : TextEvent {
|
||||
public String Text { get; private set; }
|
||||
public StringEvent(String text) => this.Text = text;
|
||||
}
|
||||
}
|
@ -2,17 +2,17 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BlubbFish.Iot.Snips.DataInputs;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.Intents {
|
||||
abstract public class AEspIntent : AIntent {
|
||||
protected readonly Dictionary<String, EnvEsp8266> esps;
|
||||
protected Dictionary<String, EnvEsp8266> esps;
|
||||
protected String espid = null;
|
||||
|
||||
protected AEspIntent(JsonData data, ABackend snips, Dictionary<String, EnvEsp8266> esps) : base(data, snips) => this.esps = esps;
|
||||
protected AEspIntent(JsonData data) : base(data) { }
|
||||
|
||||
public override void Parse() {
|
||||
public void ParseESP() {
|
||||
Console.WriteLine("AEspIntent.ParseESP(): Parse the ESP data.");
|
||||
String ort = this.slots["ort"];
|
||||
String mort = "ESP8266-" + ort;
|
||||
Dictionary<String, Double> goal = new Dictionary<String, Double>();
|
||||
@ -30,6 +30,8 @@ namespace BlubbFish.Iot.Snips.Intents {
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetEsps(Dictionary<String, EnvEsp8266> esps) => this.esps = esps;
|
||||
|
||||
protected String GetSpeakName(String name) {
|
||||
String ort = name.Substring(8);
|
||||
switch(ort) {
|
||||
|
@ -1,55 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using BlubbFish.Iot.Snips.Events;
|
||||
using BlubbFish.Utils;
|
||||
using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.Intents {
|
||||
public abstract class AIntent {
|
||||
protected readonly JsonData data;
|
||||
private readonly ABackend snips;
|
||||
protected readonly Dictionary<String, String> slots = new Dictionary<String, String>();
|
||||
|
||||
protected AIntent(JsonData data, ABackend snips) {
|
||||
this.data = data;
|
||||
this.snips = snips;
|
||||
this.ParseSlots();
|
||||
}
|
||||
public delegate void EventText(Object sender, TextEvent e);
|
||||
public delegate void EventShutdown(Object sender, EventArgs e);
|
||||
|
||||
private void ParseSlots() {
|
||||
foreach(JsonData item in this.data["slots"]) {
|
||||
public event EventText SendText;
|
||||
public event EventShutdown EndSession;
|
||||
|
||||
|
||||
protected AIntent(JsonData intentdata) => this.ParseIntent(intentdata);
|
||||
|
||||
private void ParseIntent(JsonData intentdata) {
|
||||
Console.WriteLine("AIntent.ParseIntent(): Get intent and parse data.");
|
||||
foreach(JsonData item in intentdata["slots"]) {
|
||||
this.slots.Add(item["slotName"].ToString(), item["value"]["value"].ToString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void SnipsSay(String text) {
|
||||
((ADataBackend)this.snips).Send("hermes/tts/say",
|
||||
JsonMapper.ToJson(
|
||||
new Dictionary<String, Object> {
|
||||
{ "id",this.data["id"].ToString() },
|
||||
{ "lang","de" },
|
||||
{ "sessionId", this.data["sessionId"].ToString() },
|
||||
{ "siteId","default" },
|
||||
{ "text",text }
|
||||
public static AIntent GetInstance(JsonData data) {
|
||||
String intent = "BlubbFish.Iot.Snips.Intents." + GetIntentName(data).ToUpperLower();
|
||||
Type t = null;
|
||||
try {
|
||||
t = Type.GetType(intent, true);
|
||||
} catch(System.IO.FileNotFoundException) {
|
||||
Console.Error.WriteLine("Intent " + intent + " could not load!");
|
||||
return null;
|
||||
}
|
||||
)
|
||||
);
|
||||
Console.WriteLine("TTS: " + text);
|
||||
return (AIntent)t.GetConstructor(new Type[] { typeof(JsonData) }).Invoke(new Object[] { data });
|
||||
}
|
||||
|
||||
protected void SnipsEndSpeak() {
|
||||
((ADataBackend)this.snips).Send("hermes/tts/sayFinished",
|
||||
JsonMapper.ToJson(
|
||||
new Dictionary<String, Object> {
|
||||
{ "id", this.data["id"].ToString() },
|
||||
{ "sessionId", this.data["sessionId"].ToString() }
|
||||
}
|
||||
)
|
||||
);
|
||||
Console.WriteLine("say Finished");
|
||||
public static String GetIntentName(JsonData data) {
|
||||
String i = data["intent"]["intentName"].ToString();
|
||||
return i.Substring(i.IndexOf(':')+1);
|
||||
}
|
||||
|
||||
protected void NotifyChangedAnswerText(String text) => this.SendText?.Invoke(this, new StringEvent(text));
|
||||
|
||||
protected void NotifyEndSession() => this.EndSession?.Invoke(this, new EventArgs());
|
||||
|
||||
public abstract void Parse();
|
||||
|
||||
public abstract void Answer();
|
||||
public virtual void Dispose() {
|
||||
Console.WriteLine("AIntent.Dispose(): Destroy the intent.");
|
||||
this.slots.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BlubbFish.Iot.Snips.DataInputs;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.Intents {
|
||||
public class GetHum : AEspIntent {
|
||||
public GetHum(JsonData data, ABackend snips, Dictionary<String, EnvEsp8266> esps) : base(data, snips, esps) {
|
||||
}
|
||||
public class Gethum : AEspIntent {
|
||||
public Gethum(JsonData data) : base(data) { }
|
||||
|
||||
public override void Answer() {
|
||||
public override void Parse() {
|
||||
Console.WriteLine("Gethum.Parse(): Tell the humidity.");
|
||||
this.ParseESP();
|
||||
if(this.espid != null) {
|
||||
this.SnipsSay("Die Luftfeuchtigkeit beträgt " + Math.Round(this.esps[this.espid].Humidity, 1) + " Prozent relative Luftfeuchtigkeit " + this.GetSpeakName(this.espid) + "!");
|
||||
this.NotifyChangedAnswerText("Die Luftfeuchtigkeit beträgt " + Math.Round(this.esps[this.espid].Humidity, 1) + " Prozent relative Luftfeuchtigkeit " + this.GetSpeakName(this.espid) + "!");
|
||||
} else {
|
||||
this.SnipsSay("Ich habe bisher keine Sensordaten erhalten!");
|
||||
this.NotifyChangedAnswerText("Ich habe bisher keine Sensordaten erhalten!");
|
||||
}
|
||||
this.SnipsEndSpeak();
|
||||
this.NotifyEndSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BlubbFish.Iot.Snips.DataInputs;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.Intents {
|
||||
class GetTemp : AEspIntent {
|
||||
public GetTemp(JsonData data, ABackend snips, Dictionary<String, EnvEsp8266> esps) : base(data, snips, esps) {
|
||||
}
|
||||
class Gettemp : AEspIntent {
|
||||
public Gettemp(JsonData data) : base(data) { }
|
||||
|
||||
public override void Answer() {
|
||||
public override void Parse() {
|
||||
Console.WriteLine("Gettemp.Parse(): Tell the temperatur.");
|
||||
this.ParseESP();
|
||||
if(this.espid != null) {
|
||||
this.SnipsSay(this.GetSpeakName(this.espid) + " ist es " + Math.Round(this.esps[this.espid].Temperature,1) + " Grad "+this.slots["feel"]+"!");
|
||||
this.NotifyChangedAnswerText(this.GetSpeakName(this.espid) + " ist es " + Math.Round(this.esps[this.espid].Temperature, 1) + " Grad " + this.slots["feel"] + "!");
|
||||
} else {
|
||||
this.SnipsSay("Ich habe bisher keine Sensordaten erhalten!");
|
||||
this.NotifyChangedAnswerText("Ich habe bisher keine Sensordaten erhalten!");
|
||||
}
|
||||
this.SnipsEndSpeak();
|
||||
this.NotifyEndSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,17 +8,10 @@ using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.Intents {
|
||||
public class Wetter : AIntent {
|
||||
private String wetterText;
|
||||
public Wetter(JsonData data) : base(data) { }
|
||||
|
||||
public Wetter(JsonData data, ABackend snips) : base(data, snips) {
|
||||
}
|
||||
|
||||
public override void Answer() {
|
||||
this.SnipsSay("Die Wettervorhersage für NRW Lautet:");
|
||||
this.SnipsSay(this.wetterText);
|
||||
this.SnipsEndSpeak();
|
||||
}
|
||||
public override void Parse() {
|
||||
Console.WriteLine("Wetter.Parse(): Catch the latest weather data and send that.");
|
||||
String html = null;
|
||||
String url = "https://opendata.dwd.de/weather/text_forecasts/txt/";
|
||||
|
||||
@ -56,9 +49,10 @@ namespace BlubbFish.Iot.Snips.Intents {
|
||||
}
|
||||
wetter = Encoding.UTF8.GetString(Encoding.Convert(Encoding.GetEncoding(1252), Encoding.UTF8, buffer));
|
||||
wetter = wetter.Replace("\r\r\n", "\n");
|
||||
Int32 start = wetter.IndexOf("\n\n")+2;
|
||||
Int32 start = wetter.IndexOf("Deutscher Wetterdienst");
|
||||
Int32 end = wetter.IndexOf("Detaillierter Wetterablauf") - start;
|
||||
this.wetterText = wetter.Substring(start, end);
|
||||
this.NotifyChangedAnswerText(wetter.Substring(start, end));
|
||||
this.NotifyEndSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
236
Snips/Notifier/Wetter.cs
Normal file
236
Snips/Notifier/Wetter.cs
Normal file
@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using BlubbFish.Iot.Snips.SessionHandling;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.Notifier {
|
||||
public class Wetter : PersistSession {
|
||||
public Wetter(ADataBackend snipsbackend) : base(snipsbackend) => this.StartBackgroundTask();
|
||||
public Int32[] places = { 805382056 /*Sankt Augustin*/, 805382060 /*Siegburg*/, 105314000 /*Bonn*/ };
|
||||
private readonly Dictionary<String, Dictionary<Int32, List<Weatheralert>>> alerts = new Dictionary<String, Dictionary<Int32, List<Weatheralert>>>() {
|
||||
{"warnings", new Dictionary<Int32, List<Weatheralert>>() },
|
||||
{"vorabInformation", new Dictionary<Int32, List<Weatheralert>>()}
|
||||
};
|
||||
|
||||
protected override void BackgroundRunner() {
|
||||
//this.Startup();
|
||||
/*this.PlayAudio(File.ReadAllBytes("C:\\Windows\\media\\Alarm05.wav"));
|
||||
while(!this.AudioIsPlaying) { Thread.Sleep(50); }
|
||||
while(this.AudioIsPlaying) { Thread.Sleep(50); }
|
||||
this.CreateSingleSession("Wetter", "Wetterwarnung");*/
|
||||
while(true) {
|
||||
//this.DownloadAndUnzipUpdate();
|
||||
DateTime n = DateTime.Now;
|
||||
this.ParseFiles();
|
||||
Console.WriteLine((DateTime.Now - n).TotalSeconds);
|
||||
Thread.Sleep(60000);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseFiles() {
|
||||
try {
|
||||
foreach(FileInfo file in new DirectoryInfo("wettertmp/unzip").EnumerateFiles()) {
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(file.FullName);
|
||||
foreach(XmlNode area in xml.SelectNodes("//*[local-name()='info']/*[local-name()='area']")) {
|
||||
Weatheralert alert = new Weatheralert {
|
||||
Start = DateTime.Parse(xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='onset']").InnerText),
|
||||
End = DateTime.Parse(xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='expires']").InnerText),
|
||||
Regionname = area.SelectSingleNode(".//*[local-name()='areaDesc']").InnerText,
|
||||
Level = this.GetLevel(xml.SelectSingleNode("//*[local-name()='info']")),
|
||||
Type = this.GetEventCode("GROUP", xml.SelectSingleNode("//*[local-name()='info']")),
|
||||
Urgency = xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='urgency']").InnerText,
|
||||
AltitudeStart = this.GetAltitudeStartFromAltitude(Double.Parse(area.SelectSingleNode(".//*[local-name()='altitude']").InnerText, CultureInfo.InvariantCulture)),
|
||||
Event = xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='event']").InnerText,
|
||||
Headline = xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='headline']").InnerText,
|
||||
Description = xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='description']").InnerText,
|
||||
AltitudeEnd = this.GetAltitudeEndFromCeiling(Double.Parse(area.SelectSingleNode(".//*[local-name()='ceiling']").InnerText, CultureInfo.InvariantCulture)),
|
||||
StateShort = this.GetGeocode("STATE", area),
|
||||
Instruction = xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='instruction']").InnerText,
|
||||
State = this.GetState(area),
|
||||
Ii = Int32.Parse(this.GetEventCode("II", xml.SelectSingleNode("//*[local-name()='info']"))),
|
||||
Published = DateTime.Parse(xml.SelectSingleNode("//*[local-name()='info']/*[local-name()='effective']").InnerText),
|
||||
WarnCellId = Int32.Parse(this.GetGeocode("WARNCELLID", area) == "" ? "0" : this.GetGeocode("WARNCELLID", area))
|
||||
};
|
||||
if(alert.Regionname != "polygonal event area") {
|
||||
if(alert.Urgency == "Immediate") {
|
||||
if(!this.alerts["warnings"].ContainsKey(alert.WarnCellId)) {
|
||||
this.alerts["warnings"].Add(alert.WarnCellId, new List<Weatheralert>());
|
||||
}
|
||||
this.alerts["warnings"][alert.WarnCellId].Add(alert);
|
||||
} else {
|
||||
if(!this.alerts["vorabInformation"].ContainsKey(alert.WarnCellId)) {
|
||||
this.alerts["vorabInformation"].Add(alert.WarnCellId, new List<Weatheralert>());
|
||||
}
|
||||
this.alerts["vorabInformation"][alert.WarnCellId].Add(alert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Utils.Helper.WriteError(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private String GetState(XmlNode area) {
|
||||
String stateShort = this.GetGeocode("STATE", area);
|
||||
switch(stateShort) {
|
||||
case "NRW":
|
||||
return "Nordrhein-Westfalen";
|
||||
case "RP":
|
||||
return "Rheinland-Pfalz";
|
||||
case "BY":
|
||||
return "Bayern";
|
||||
case "BW":
|
||||
return "Baden-Württemberg";
|
||||
case "HE":
|
||||
return "Hessen";
|
||||
case "SN":
|
||||
return "Sachsen";
|
||||
case "TH":
|
||||
return "Thüringen";
|
||||
case "NS":
|
||||
return "Niedersachsen";
|
||||
case "HH":
|
||||
return "Hamburg";
|
||||
case "HB":
|
||||
return "Bremen";
|
||||
case "SH":
|
||||
return "Schleswig-Holstein";
|
||||
case "SL":
|
||||
return "Saarland";
|
||||
case "SA":
|
||||
return "Sachsen-Anhalt";
|
||||
case "BB":
|
||||
return "Brandenburg";
|
||||
case "BL":
|
||||
return "Berlin";
|
||||
case "MV":
|
||||
return "Mecklenburg-Vorpomern";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String GetGeocode(String geocode, XmlNode area) {
|
||||
foreach(XmlNode code in area.SelectNodes(".//*[local-name()='geocode']")) {
|
||||
if(code.SelectSingleNode(".//*[local-name()='valueName']").InnerText == geocode) {
|
||||
return code.SelectSingleNode(".//*[local-name()='value']").InnerText;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private Double? GetAltitudeEndFromCeiling(Double ceiling) {
|
||||
Double result = Math.Round(ceiling * 0.3048);
|
||||
if(result == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private Double? GetAltitudeStartFromAltitude(Double altitude) {
|
||||
Double result = Math.Round(altitude * 0.3048);
|
||||
if(result == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private String GetEventCode(String eventCode, XmlNode info) {
|
||||
foreach(XmlNode code in info.SelectNodes(".//*[local-name()='eventCode']")) {
|
||||
if(code.SelectSingleNode(".//*[local-name()='valueName']").InnerText == eventCode) {
|
||||
return code.SelectSingleNode(".//*[local-name()='value']").InnerText;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private Int32 GetLevel(XmlNode info) {
|
||||
if(info.SelectSingleNode(".//*[local-name()='urgency']").InnerText == "Future") {
|
||||
return 1;
|
||||
} else {
|
||||
switch(info.SelectSingleNode(".//*[local-name()='severity']").InnerText) {
|
||||
case "Minor": return 2;
|
||||
case "Moderate": return 3;
|
||||
case "Severe": return 4;
|
||||
case "Extreme": return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadAndUnzipUpdate() {
|
||||
try {
|
||||
HttpWebRequest requestw = (HttpWebRequest)WebRequest.Create("https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_DWD_STAT/Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMDWD_COMMUNEUNION_DE.zip");
|
||||
using(HttpWebResponse response = (HttpWebResponse)requestw.GetResponse()) {
|
||||
String date = DateTime.Parse(response.Headers.Get("Last-Modified")).ToFileTime().ToString();
|
||||
if(!File.Exists("wettertmp/zip/" + date + ".zip")) {
|
||||
this.ClearFiles();
|
||||
using(Stream stream = response.GetResponseStream())
|
||||
using(FileStream filestream = File.OpenWrite("wettertmp/zip/" + date + ".zip")) {
|
||||
stream.CopyTo(filestream);
|
||||
filestream.Flush();
|
||||
filestream.Close();
|
||||
}
|
||||
ZipFile.ExtractToDirectory("wettertmp/zip/" + date + ".zip", "wettertmp/unzip");
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Utils.Helper.WriteError(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearFiles() {
|
||||
foreach(FileInfo file in new DirectoryInfo("wettertmp/zip").EnumerateFiles()) {
|
||||
file.Delete();
|
||||
}
|
||||
foreach(FileInfo file in new DirectoryInfo("wettertmp/unzip").EnumerateFiles()) {
|
||||
file.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void Startup() {
|
||||
if(!Directory.Exists("wettertmp")) {
|
||||
Directory.CreateDirectory("wettertmp");
|
||||
}
|
||||
if(!Directory.Exists("wettertmp/zip")) {
|
||||
Directory.CreateDirectory("wettertmp/zip");
|
||||
}
|
||||
if(!Directory.Exists("wettertmp/unzip")) {
|
||||
Directory.CreateDirectory("wettertmp/unzip");
|
||||
}
|
||||
this.ClearFiles();
|
||||
}
|
||||
|
||||
private struct Weatheralert {
|
||||
public DateTime Start { get; set; }
|
||||
public DateTime End { get; set; }
|
||||
public String Regionname { get; set; }
|
||||
public Int32 Level { get; set; }
|
||||
public String Type { get; set; }
|
||||
public Double? AltitudeStart { get; set; }
|
||||
public String Event { get; set; }
|
||||
public String Headline { get; set; }
|
||||
public String Description { get; set; }
|
||||
public Double? AltitudeEnd { get; set; }
|
||||
public String StateShort { get; set; }
|
||||
public String Instruction { get; set; }
|
||||
public String State { get; set; }
|
||||
public Int32 Ii { get; set; }
|
||||
public DateTime Published { get; set; }
|
||||
public Int32 WarnCellId { get; set; }
|
||||
public String Urgency { get; set; }
|
||||
|
||||
public override String ToString() => this.Regionname+" ("+this.WarnCellId+"): "+this.Headline;
|
||||
}
|
||||
}
|
||||
}
|
@ -20,7 +20,11 @@ namespace BlubbFish.Iot.Snips {
|
||||
InIReader backends = InIReader.GetInstance("backends");
|
||||
Dictionary<String, ABackend> sources = new Dictionary<String, ABackend>();
|
||||
foreach(String item in backends.GetSections(false)) {
|
||||
sources.Add(item, ABackend.GetInstance(backends.GetSection(item), ABackend.BackendType.Data));
|
||||
Dictionary<String, String> sourcesettings = backends.GetSection(item);
|
||||
if(item == "snips") {
|
||||
sourcesettings.Add("topic", "hermes/dialogueManager/sessionStarted;hermes/intent/#;hermes/dialogueManager/sessionEnded;hermes/audioServer/default/playBytes/+;hermes/audioServer/default/playFinished;hermes/tts/say;hermes/tts/sayFinished");
|
||||
}
|
||||
sources.Add(item, ABackend.GetInstance(sourcesettings, ABackend.BackendType.Data));
|
||||
}
|
||||
SnipsBot s = new SnipsBot(sources, InIReader.GetInstance("settings").GetSection("general"));
|
||||
s.Dispose();
|
||||
|
72
Snips/SessionHandling/PersistSession.cs
Normal file
72
Snips/SessionHandling/PersistSession.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.SessionHandling {
|
||||
abstract public class PersistSession : Session {
|
||||
private Thread bgthread;
|
||||
|
||||
|
||||
public PersistSession(ADataBackend snipsmqtt) : base("", "default", snipsmqtt) {
|
||||
Console.WriteLine("PersistSession.PersistSession(): Start a Persist Session.");
|
||||
this.CustomId = "PersistSession."+this.GetType().Name;
|
||||
}
|
||||
|
||||
protected void CreateSingleSession(String customData, String text) {
|
||||
Console.WriteLine("PersistSession.CreateSingleSession(): Send request to end the session.");
|
||||
this.SnipsBackend.Send("hermes/dialogueManager/startSession", JsonMapper.ToJson(
|
||||
new Dictionary<String, Object> {
|
||||
{ "siteId", "default" },
|
||||
{ "customData", this.CustomId },
|
||||
{ "init", new Dictionary<String, Object> {
|
||||
{ "type", "notification" },
|
||||
{ "text", text }
|
||||
}}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
protected void StartBackgroundTask() {
|
||||
this.bgthread = new Thread(this.BackgroundRunner);
|
||||
this.bgthread.Start();
|
||||
}
|
||||
|
||||
protected abstract void BackgroundRunner();
|
||||
|
||||
public static List<String> GetNotfierList() {
|
||||
List<String> list = new List<String>();
|
||||
foreach(Type t in Assembly.GetExecutingAssembly().GetTypes()) {
|
||||
if(t.Namespace == "BlubbFish.Iot.Snips.Notifier" && t.Name != "ANotifier" && !t.IsNested) {
|
||||
list.Add(t.Name);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static PersistSession GetInstance(String @class, ADataBackend snipsmqtt) {
|
||||
String intent = "BlubbFish.Iot.Snips.Notifier." + @class;
|
||||
Type t = null;
|
||||
try {
|
||||
t = Type.GetType(intent, true);
|
||||
} catch(System.IO.FileNotFoundException) {
|
||||
Console.Error.WriteLine("Notifier " + intent + " could not load!");
|
||||
return null;
|
||||
}
|
||||
return (PersistSession)t.GetConstructor(new Type[] { typeof(ADataBackend) }).Invoke(new Object[] { snipsmqtt });
|
||||
}
|
||||
|
||||
public void SetSessionId(String sessionid) => this.SessionId = sessionid;
|
||||
|
||||
public void SetSideId(String siteid) => this.SiteId = siteid;
|
||||
|
||||
public override void Dispose() {
|
||||
if(this.bgthread != null) {
|
||||
this.bgthread.Abort();
|
||||
}
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
100
Snips/SessionHandling/Session.cs
Normal file
100
Snips/SessionHandling/Session.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BlubbFish.Iot.Snips.Events;
|
||||
using BlubbFish.Iot.Snips.Intents;
|
||||
using BlubbFish.Utils;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using BlubbFish.Utils.IoT.Connector.Data;
|
||||
using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.SessionHandling {
|
||||
public class Session {
|
||||
protected readonly ADataBackend SnipsBackend;
|
||||
public String CustomId { get; protected set; }
|
||||
public String SessionId { get; protected set; }
|
||||
public String SiteId { get; protected set; }
|
||||
public AIntent Intent { get; private set; }
|
||||
public Boolean AudioIsPlaying { get; private set; }
|
||||
public Boolean TtsIsPlaying { get; private set; }
|
||||
|
||||
public Session(String sessionId, String siteId, ADataBackend snipsmqtt) {
|
||||
Console.WriteLine("Session.Session(): Start a new session.");
|
||||
this.SessionId = sessionId;
|
||||
this.SiteId = siteId;
|
||||
this.CustomId = "";
|
||||
this.SnipsBackend = snipsmqtt;
|
||||
this.AudioIsPlaying = false;
|
||||
this.TtsIsPlaying = false;
|
||||
}
|
||||
|
||||
public void AddIntent(JsonData data, Dictionary<String, DataInputs.EnvEsp8266> esps) {
|
||||
Console.WriteLine("Session.AddIntent(): Create intent " + data["intent"]["intentName"].ToString()+".");
|
||||
this.Intent = AIntent.GetInstance(data);
|
||||
if(this.Intent.GetType().HasAbstract(typeof(AEspIntent))) {
|
||||
((AEspIntent)this.Intent).SetEsps(esps);
|
||||
}
|
||||
this.Intent.SendText += this.ContinueSession;
|
||||
this.Intent.EndSession += this.EndSession;
|
||||
this.Intent.Parse();
|
||||
}
|
||||
|
||||
private void EndSession(Object sender, EventArgs e) {
|
||||
Console.WriteLine("Session.EndSession(): Send request to end the session.");
|
||||
this.SnipsBackend.Send("hermes/dialogueManager/endSession",
|
||||
JsonMapper.ToJson(
|
||||
new Dictionary<String, Object> {
|
||||
{ "sessionId", this.SessionId }
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void ContinueSession(Object sender, TextEvent e) {
|
||||
Console.WriteLine("Session.ContinueSession(): Continue session with text: (" + ((StringEvent)e).Text.Replace("\n", "") + ").");
|
||||
this.SnipsBackend.Send("hermes/dialogueManager/continueSession",
|
||||
JsonMapper.ToJson(
|
||||
new Dictionary<String, Object> {
|
||||
{ "sessionId", this.SessionId },
|
||||
{ "text", ((StringEvent)e).Text }
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected void PlayAudio(Byte[] wav) {
|
||||
Console.WriteLine("Session.PlayAudio(): Play an Audio Stream.");
|
||||
((Mqtt)this.SnipsBackend).Send("hermes/audioServer/default/playBytes/" + this.CustomId, wav);
|
||||
}
|
||||
|
||||
public virtual void Dispose() {
|
||||
Console.WriteLine("Session.Dispose(): Destroy the current session.");
|
||||
if(this.Intent != null) {
|
||||
this.Intent.SendText -= this.ContinueSession;
|
||||
this.Intent.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void AudioIsBusy() {
|
||||
Console.WriteLine("Session.AudioIsBusy(): Notify Session that the Audiodevice is busy.");
|
||||
this.AudioIsPlaying = true;
|
||||
}
|
||||
|
||||
public void AudioIsFree() {
|
||||
Console.WriteLine("Session.AudioIsFree(): Notify Session that the Audiodevice is free.");
|
||||
this.AudioIsPlaying = false;
|
||||
}
|
||||
|
||||
|
||||
internal void TtsIsFree() {
|
||||
Console.WriteLine("Session.TtsIsFree(): Notify Session that the TTS-Engine is free.");
|
||||
this.TtsIsPlaying = false;
|
||||
}
|
||||
|
||||
internal void TtsIsBusy() {
|
||||
Console.WriteLine("Session.TtsIsBusy(): Notify Session that the TTS-Engine is busy.");
|
||||
this.TtsIsPlaying = true;
|
||||
}
|
||||
}
|
||||
}
|
101
Snips/SessionHandling/SessionManager.cs
Normal file
101
Snips/SessionHandling/SessionManager.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BlubbFish.Utils;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips.SessionHandling {
|
||||
public class SessionManager {
|
||||
private readonly ADataBackend snipsmqtt;
|
||||
private readonly Dictionary<String, Session> sessions = new Dictionary<String, Session>();
|
||||
|
||||
public SessionManager(ABackend snipsbackend) {
|
||||
this.snipsmqtt = (ADataBackend)snipsbackend;
|
||||
this.StartNotifier();
|
||||
}
|
||||
|
||||
private void StartNotifier() {
|
||||
foreach(String item in PersistSession.GetNotfierList()) {
|
||||
this.sessions.Add("PersistSession."+item, PersistSession.GetInstance(item, this.snipsmqtt));
|
||||
}
|
||||
}
|
||||
|
||||
public void SessionStarted(JsonData data) {
|
||||
Console.WriteLine("SessionManager.SessionStarted(): Start a new session with sessionId: " + data["sessionId"].ToString() + ".");
|
||||
String sessionid = data["sessionId"].ToString();
|
||||
if(data["customData"].IsString && this.sessions.ContainsKey(data["customData"].ToString()) && this.sessions[data["customData"].ToString()].GetType().HasAbstract(typeof(PersistSession))) {
|
||||
((PersistSession)this.sessions[data["customData"].ToString()]).SetSessionId(sessionid);
|
||||
((PersistSession)this.sessions[data["customData"].ToString()]).SetSideId(data["siteId"].ToString());
|
||||
} else {
|
||||
if(this.sessions.ContainsKey(sessionid)) {
|
||||
throw new Exception("BlubbFish.Iot.Snips.SessionHandling.SessionManager.SessionStarted(): Session is already there!");
|
||||
} else {
|
||||
this.sessions.Add(sessionid, new Session(sessionid, data["siteId"].ToString(), this.snipsmqtt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Intent(JsonData data, Dictionary<String, DataInputs.EnvEsp8266> esps) {
|
||||
Console.WriteLine("SessionManager.Intent(): Attach an intent to the session sessionId: " + data["sessionId"].ToString() + ".");
|
||||
String sessionid = data["sessionId"].ToString();
|
||||
if(data["customData"].IsString && this.sessions.ContainsKey(data["customData"].ToString()) && this.sessions[data["customData"].ToString()].GetType().HasAbstract(typeof(PersistSession)) && this.sessions[data["customData"].ToString()].SessionId == sessionid) {
|
||||
sessionid = data["customData"].ToString();
|
||||
}
|
||||
if(!this.sessions.ContainsKey(sessionid)) {
|
||||
throw new Exception("BlubbFish.Iot.Snips.SessionHandling.SessionManager.Intent(): Sessionid not found!");
|
||||
} else {
|
||||
this.sessions[sessionid].AddIntent(data, esps);
|
||||
}
|
||||
}
|
||||
|
||||
internal void NotifyTtsIsSpeaking() {
|
||||
Console.WriteLine("SessionManager.NotifyTtsIsSpeaking(): Notify all Sessions and Notifier that TTS is busy.");
|
||||
foreach(KeyValuePair<String, Session> item in this.sessions) {
|
||||
item.Value.TtsIsBusy();
|
||||
}
|
||||
}
|
||||
|
||||
internal void NotifyTtsIsEnded() {
|
||||
Console.WriteLine("SessionManager.NotifyTtsIsEnded(): Notify all Sessions and Notifier that TTs is free.");
|
||||
foreach(KeyValuePair<String, Session> item in this.sessions) {
|
||||
item.Value.TtsIsFree();
|
||||
}
|
||||
}
|
||||
|
||||
internal void NotifyAudioIsEnded() {
|
||||
Console.WriteLine("SessionManager.NotifyAudioIsEnded(): Notify all Sessions and Notifier that Audio is free.");
|
||||
foreach(KeyValuePair<String, Session> item in this.sessions) {
|
||||
item.Value.AudioIsFree();
|
||||
}
|
||||
}
|
||||
|
||||
internal void NotifyAudioIsPlaying() {
|
||||
Console.WriteLine("SessionManager.NotifyAudioIsPlaying(): Notify all Sessions and Notifier that Audio is busy.");
|
||||
foreach(KeyValuePair<String, Session> item in this.sessions) {
|
||||
item.Value.AudioIsBusy();
|
||||
}
|
||||
}
|
||||
|
||||
public void SessionEnded(JsonData data) {
|
||||
Console.WriteLine("SessionManager.SessionEnded(): Destroy the session with sessionId: " + data["sessionId"].ToString() + ".");
|
||||
String sessionid = data["sessionId"].ToString();
|
||||
if(data["customData"].IsString && this.sessions.ContainsKey(data["customData"].ToString()) && this.sessions[data["customData"].ToString()].GetType().HasAbstract(typeof(PersistSession)) && this.sessions[data["customData"].ToString()].SessionId == sessionid) {
|
||||
((PersistSession)this.sessions[data["customData"].ToString()]).SetSessionId("");
|
||||
((PersistSession)this.sessions[data["customData"].ToString()]).SetSideId("default");
|
||||
} else {
|
||||
if(!this.sessions.ContainsKey(sessionid)) {
|
||||
throw new Exception("BlubbFish.Iot.Snips.SessionHandling.SessionManager.SessionEnded(): Sessionid not found!");
|
||||
} else {
|
||||
this.sessions[sessionid].Dispose();
|
||||
this.sessions.Remove(sessionid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
foreach(KeyValuePair<String, Session> item in this.sessions) {
|
||||
item.Value.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@ -44,14 +45,19 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DataInputs\EnvEsp8266.cs" />
|
||||
<Compile Include="Events\TextEvent.cs" />
|
||||
<Compile Include="Helper\Texthelper.cs" />
|
||||
<Compile Include="Intents\AEspIntent.cs" />
|
||||
<Compile Include="Intents\AIntent.cs" />
|
||||
<Compile Include="Intents\GetHum.cs" />
|
||||
<Compile Include="Intents\GetTemp.cs" />
|
||||
<Compile Include="Intents\Wetter.cs" />
|
||||
<Compile Include="Notifier\Wetter.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SessionHandling\PersistSession.cs" />
|
||||
<Compile Include="SessionHandling\Session.cs" />
|
||||
<Compile Include="SessionHandling\SessionManager.cs" />
|
||||
<Compile Include="SnipsBot.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -92,6 +98,7 @@
|
||||
<None Include="dpkg\postinst" />
|
||||
<None Include="dpkg\preinst" />
|
||||
<None Include="dpkg\prerm" />
|
||||
<None Include="json1.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BlubbFish.Iot.Snips.DataInputs;
|
||||
using BlubbFish.Iot.Snips.Intents;
|
||||
using BlubbFish.Iot.Snips.SessionHandling;
|
||||
using BlubbFish.Utils.IoT.Bots;
|
||||
using BlubbFish.Utils.IoT.Connector;
|
||||
using BlubbFish.Utils.IoT.Events;
|
||||
@ -9,34 +9,39 @@ using LitJson;
|
||||
|
||||
namespace BlubbFish.Iot.Snips {
|
||||
class SnipsBot : MultiSourceBot {
|
||||
private readonly Boolean debug = true;
|
||||
private readonly Boolean debug = false;
|
||||
private readonly Dictionary<String, EnvEsp8266> esps = new Dictionary<String, EnvEsp8266>();
|
||||
private readonly SessionManager sessions;
|
||||
|
||||
public SnipsBot(Dictionary<String, ABackend> sources, Dictionary<String, String> settings) : base(sources, settings) {
|
||||
this.logger.SetPath(settings["loggingpath"]);
|
||||
this.sources["snips"].MessageIncomming += this.IntentWorker;
|
||||
this.sources["iot"].MessageIncomming += this.GetEspData;
|
||||
this.sessions = new SessionManager(sources["snips"]);
|
||||
this.WaitForShutdown();
|
||||
}
|
||||
|
||||
private void IntentWorker(Object sender, BackendEvent e) {
|
||||
if(e.From.ToString().StartsWith("hermes/audioServer/default/playBytes/")) {
|
||||
this.sessions.NotifyAudioIsPlaying();
|
||||
} else {
|
||||
try {
|
||||
JsonData data = JsonMapper.ToObject(e.Message);
|
||||
AIntent intent = null;
|
||||
if(data["intent"]["intentName"].ToString() == "blubbfish:GetTemp") {
|
||||
intent = new GetTemp(data, this.sources["snips"], this.esps);
|
||||
} else if(data["intent"]["intentName"].ToString() == "blubbfish:GetHum") {
|
||||
intent = new GetHum(data, this.sources["snips"], this.esps);
|
||||
} else if(data["intent"]["intentName"].ToString() == "blubbfish:Wetter") {
|
||||
intent = new Wetter(data, this.sources["snips"]);
|
||||
if(e.From.ToString() == "hermes/dialogueManager/sessionStarted") {
|
||||
this.sessions.SessionStarted(data);
|
||||
} else if(e.From.ToString().StartsWith("hermes/intent/")) {
|
||||
this.sessions.Intent(data, this.esps);
|
||||
} else if(e.From.ToString() == "hermes/dialogueManager/sessionEnded") {
|
||||
this.sessions.SessionEnded(data);
|
||||
} else if(e.From.ToString() == "hermes/audioServer/default/playFinished") {
|
||||
this.sessions.NotifyAudioIsEnded();
|
||||
} else if(e.From.ToString() == "hermes/tts/say") {
|
||||
this.sessions.NotifyTtsIsSpeaking();
|
||||
} else if(e.From.ToString() == "hermes/tts/sayFinished") {
|
||||
this.sessions.NotifyTtsIsEnded();
|
||||
}
|
||||
if(intent != null) {
|
||||
Console.WriteLine("Intent Start " + data["intent"]["intentName"].ToString());
|
||||
intent.Parse();
|
||||
intent.Answer();
|
||||
Console.WriteLine("Intent Finished!");
|
||||
} catch(Exception ex) { Utils.Helper.WriteError(ex.Message); }
|
||||
}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
private void GetEspData(Object sender, BackendEvent e) {
|
||||
@ -55,6 +60,7 @@ namespace BlubbFish.Iot.Snips {
|
||||
}
|
||||
|
||||
public override void Dispose() {
|
||||
this.sessions.Dispose();
|
||||
foreach(KeyValuePair<String, ABackend> item in this.sources) {
|
||||
item.Value.Dispose();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
[snips]
|
||||
type=mqtt
|
||||
server=localhost
|
||||
topic=hermes/nlu/intentParsed
|
||||
topic=hermes/intent/#
|
25
Snips/json1.json
Normal file
25
Snips/json1.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"time": "1559769902000",
|
||||
"warnings": { "805382056": null },
|
||||
"vorabInformation": {
|
||||
"805382056": [
|
||||
{
|
||||
"start": 1559761200000,
|
||||
"end": 1559793600000,
|
||||
"regionName": "Stadt Sankt Augustin",
|
||||
"level": 1,
|
||||
"type": "THUNDERSTORM",
|
||||
"altitudeStart": null,
|
||||
"event": "VORABINFORMATION SCHWERES GEWITTER",
|
||||
"headline": "VORABINFORMATION UNWETTER vor SCHWEREM GEWITTER",
|
||||
"description": "Ab Mittwochabend k\u00f6nnen aus S\u00fcden teils schwere Gewitter aufziehen. Dabei k\u00f6nnen \u00f6rtlich heftiger Starkregen (30 bis 40 l\/qm in kurzer Zeit), mittelgro\u00dfer Hagel und orkanartige B\u00f6en (um 110 km\/h) auftreten. Auch einzelne Tornados sind nicht ausgeschlossen. Die Gewitterneigung bleibt bis in die Morgenstunden des Donnerstags bestehen.\n\n\nDies ist eine Vorabinformation. Sie wird herausgegeben, wenn ein Unwetterereignis wahrscheinlich ist, die Unsicherheiten betreffend Zeit, Gebiet und Intensit\u00e4t aber noch gro\u00df sind. Unwetterwarnungen werden bei Bedarf zeitnah ausgegeben.\n\nF\u00fcr diese Vorabinformation wird es voraussichtlich keine Aktualisierung geben.",
|
||||
"altitudeEnd": null,
|
||||
"stateShort": "",
|
||||
"instruction": "Dies ist ein Hinweis auf eine Wetterlage mit hohem Unwetterpotential. Er soll die rechtzeitige Vorbereitung von Schutzma\u00dfnahmen erm\u00f6glichen. \n\nGewitter mit den genannten Begleiterscheinungen treten typischerweise sehr lokal auf und treffen mit voller Intensit\u00e4t meist nur wenige Orte. Genauere Angaben zu Ort, Gebiet und Zeitpunkt des Ereignisses k\u00f6nnen erst mit der Ausgabe der amtlichen Warnungen erfolgen. Bitte verfolgen Sie die weiteren Wettervorhersagen mit besonderer Aufmerksamkeit.",
|
||||
"state": null,
|
||||
"ii": 40,
|
||||
"published": 1559718420000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user