[NF] Zway-Bot hinzugefügt

[NF] Viele kleine Änderungen an Zwaylib zur Verbesserung der Kompatibilität
This commit is contained in:
BlubbFish 2017-11-25 11:00:48 +00:00
commit 9fb1782abe
8 changed files with 556 additions and 0 deletions

37
Zway-Bot.sln Normal file
View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zway-Bot", "Zway-Bot\Zway-Bot.csproj", "{AEF8059F-8AEF-45C7-85C4-318C8F797900}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zway", "..\Zway\Zway\Zway.csproj", "{166258ED-CB3D-43F5-8E8D-3A993B64D022}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "..\Utils\Utils\Utils.csproj", "{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AEF8059F-8AEF-45C7-85C4-318C8F797900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AEF8059F-8AEF-45C7-85C4-318C8F797900}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AEF8059F-8AEF-45C7-85C4-318C8F797900}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AEF8059F-8AEF-45C7-85C4-318C8F797900}.Release|Any CPU.Build.0 = Release|Any CPU
{166258ED-CB3D-43F5-8E8D-3A993B64D022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{166258ED-CB3D-43F5-8E8D-3A993B64D022}.Debug|Any CPU.Build.0 = Debug|Any CPU
{166258ED-CB3D-43F5-8E8D-3A993B64D022}.Release|Any CPU.ActiveCfg = Release|Any CPU
{166258ED-CB3D-43F5-8E8D-3A993B64D022}.Release|Any CPU.Build.0 = Release|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FC298685-EC11-4957-9D91-F044DDDD0B6E}
EndGlobalSection
EndGlobal

190
Zway-Bot/CronJob.cs Normal file
View File

@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Threading;
using BlubbFish.IoT.Zway;
using BlubbFish.IoT.Zway.Interfaces;
using BlubbFish.Utils;
namespace ZwayBot {
internal class CronJob : IDisposable {
private ZwayController zw;
private InIReader ini;
private DateTime crontime;
private Thread thread;
public delegate void CronRunned(Object sender, CronEvent e);
public event CronRunned Update;
private Dictionary<String, String> cron_named = new Dictionary<String, String> {
{ "@yearly", "0 0 1 1 *" },
{ "@annually", "0 0 1 1 *" },
{ "@monthly", "0 0 1 * *" },
{ "@weekly", "0 0 * * 0" },
{ "@daily", "0 0 * * *" },
{ "@hourly", "0 * * * *" }
};
public CronJob(ZwayController zw) {
this.zw = zw;
this.ini = InIReader.GetInstance("cron.ini");
this.crontime = DateTime.Now;
this.thread = new Thread(this.Runner);
this.thread.Start();
}
private void Runner() {
Thread.Sleep(DateTime.Now.AddMinutes(1).AddSeconds(DateTime.Now.Second * (-1)).AddMilliseconds(DateTime.Now.Millisecond * (-1)) - DateTime.Now);
while (true) {
if(this.crontime.Minute < DateTime.Now.Minute) {
this.crontime = DateTime.Now;
foreach (String item in this.ini.GetSections()) {
if(ParseCronString(this.ini.GetValue(item, "cron"))) {
this.SetValues(this.ini.GetValue(item, "set"));
}
}
}
Thread.Sleep(100);
}
}
private void SetValues(String value) {
foreach (String item in value.Split(';')) {
String[] items = item.Split(':');
if(items.Length == 2) {
String[] addr = items[0].Split('-');
String[] values = items[1].Split('-');
if(addr.Length == 3 || addr.Length == 4) {
Int32 deviceid = Int32.Parse(addr[0]);
Int32 instanceid = Int32.Parse(addr[1]);
Int32 classid = Int32.Parse(addr[2]);
ICommandClass c;
if(addr.Length == 4) {
Int32 subcid = Int32.Parse(addr[3]);
c = this.zw.GetCommandClassSub(deviceid, instanceid, classid, subcid);
} else {
c = this.zw.GetCommandClass(deviceid, instanceid, classid);
}
if (c != null && values.Length == 2) {
if (Helper.HasProperty(c, values[0])) {
Helper.SetProperty(c, values[0], values[1]);
this.Update?.Invoke(this, new CronEvent(items[0], values[0], values[1]));
}
}
}
}
}
}
private Boolean ParseCronString(String str) {
str = str.Trim();
if(this.cron_named.ContainsKey(str)) {
str = this.cron_named[str];
}
String[] value = str.Split(' ');
if(value.Length != 5) {
return false;
}
if (!this.CheckDateStr(this.crontime.ToString("mm"), value[0], "0-59")) {
return false;
}
if (!this.CheckDateStr(this.crontime.ToString("HH"), value[1], "0-23")) {
return false;
}
if (!this.CheckDateStr(this.crontime.ToString("MM"), value[3], "1-12")) {
return false;
}
if (value[2] != "*" && value[4] != "*") {
if (!this.CheckDateStr(this.crontime.ToString("dd"), value[2], "1-31") && !this.CheckDateStr(((Int32)this.crontime.DayOfWeek).ToString(), value[4], "0-7")) {
return false;
}
} else {
if (!this.CheckDateStr(this.crontime.ToString("dd"), value[2], "1-31")) {
return false;
}
if (!this.CheckDateStr(((Int32)this.crontime.DayOfWeek).ToString(), value[4], "0-7")) {
return false;
}
}
return true;
}
private Boolean CheckDateStr(String date, String cron, String limit) {
cron = cron.ToLower();
for (Int32 i = 0; i <= 6; i++) {
cron = cron.Replace(DateTime.Parse("2015-01-" + (4 + i) + "T00:00:00").ToString("ddd", CultureInfo.CreateSpecificCulture("en-US")), i.ToString());
cron = cron.Replace(DateTime.Parse("2015-01-" + (4 + i) + "T00:00:00").ToString("dddd", CultureInfo.CreateSpecificCulture("en-US")), i.ToString());
}
for (Int32 i = 1; i <= 12; i++) {
cron = cron.Replace(DateTime.Parse("2015-"+i+"-01T00:00:00").ToString("MMM", CultureInfo.CreateSpecificCulture("en-US")), i.ToString());
cron = cron.Replace(DateTime.Parse("2015-" + i + "-01T00:00:00").ToString("MMMM", CultureInfo.CreateSpecificCulture("en-US")), i.ToString());
}
if (cron.Contains("*")) {
cron = cron.Replace("*", limit);
}
if(cron.Contains("-")) {
MatchCollection m = new Regex("(\\d+)-(\\d+)").Matches(cron);
foreach (Match p in m) {
List<String> s = new List<String>();
for(Int32 i=Math.Min(Int32.Parse(p.Groups[1].Value), Int32.Parse(p.Groups[2].Value));i<= Math.Max(Int32.Parse(p.Groups[1].Value), Int32.Parse(p.Groups[2].Value)); i++) {
s.Add(i.ToString());
}
cron = cron.Replace(p.Groups[0].Value, String.Join(",", s));
}
}
Int32 match = 0;
if(cron.Contains("/")) {
Match m = new Regex("/(\\d+)").Match(cron);
cron = cron.Replace(m.Groups[0].Value, "");
match = Int32.Parse(m.Groups[1].Value);
}
Dictionary<Int32, String> ret = new Dictionary<Int32, String>();
if(!cron.Contains(",")) {
ret.Add(Int32.Parse(cron), "");
} else {
foreach (String item in cron.Split(',')) {
if(!ret.ContainsKey(Int32.Parse(item))) {
ret.Add(Int32.Parse(item), "");
}
}
}
if(match != 0) {
Dictionary<Int32, String> r = new Dictionary<Int32, String>();
foreach (KeyValuePair<Int32, String> item in ret) {
if(item.Key%match == 0) {
r.Add(item.Key, "");
}
}
ret = r;
}
return ret.ContainsKey(Int32.Parse(date));
}
#region IDisposable Support
private Boolean disposedValue = false; // Dient zur Erkennung redundanter Aufrufe.
protected virtual void Dispose(Boolean disposing) {
if (!this.disposedValue) {
if (disposing) {
this.thread.Abort();
while(this.thread.ThreadState != ThreadState.Aborted) { Thread.Sleep(100); }
}
this.thread = null;
this.disposedValue = true;
}
}
~CronJob() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}

34
Zway-Bot/Events.cs Normal file
View File

@ -0,0 +1,34 @@
using System;
namespace ZwayBot {
public class CronEvent : EventArgs {
public CronEvent() {
}
public CronEvent(String addr, String prop, String value) {
this.Address = addr;
this.Property = prop;
this.Value = value;
}
public String Address { get; }
public String Property { get; }
public String Value { get; }
}
public class OvertakerEvent : EventArgs {
public OvertakerEvent() {
}
public OvertakerEvent(String addr, String prop, String value) {
this.Address = addr;
this.Property = prop;
this.Value = value;
}
public String Address { get; }
public String Property { get; }
public String Value { get; }
}
}

48
Zway-Bot/Helper.cs Normal file
View File

@ -0,0 +1,48 @@
using System;
using System.Reflection;
namespace ZwayBot {
class Helper {
public static void SetProperty(Object o, String name, String value) {
PropertyInfo prop = o.GetType().GetProperty(name);
if (prop.CanWrite) {
if (prop.PropertyType == typeof(Boolean) && Boolean.TryParse(value, out Boolean vb)) {
prop.SetValue(o, vb);
} else if (prop.PropertyType == typeof(Int32) && Int32.TryParse(value, out Int32 v32)) {
prop.SetValue(o, v32);
} else if (prop.PropertyType == typeof(Single) && Single.TryParse(value, out Single vs)) {
prop.SetValue(o, vs);
} else if (prop.PropertyType == typeof(Int64) && Int64.TryParse(value, out Int64 v64)) {
prop.SetValue(o, v64);
}
}
}
public static Boolean HasProperty(Object o, String type) {
Type t = o.GetType();
foreach (PropertyInfo item in t.GetProperties()) {
if (item.Name == type) {
return true;
}
}
return false;
}
internal static Object GetProperty(Object o, String name) {
PropertyInfo prop = o.GetType().GetProperty(name);
if(prop.CanRead) {
return prop.GetValue(o);
}
return null;
}
internal static Boolean HasInterface(Object o, String type) {
Type t = o.GetType();
foreach (Type item in t.GetInterfaces()) {
if(item.Name == type) {
return true;
}
}
return false;
}
}
}

106
Zway-Bot/Overtaker.cs Normal file
View File

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using BlubbFish.IoT.Zway;
using BlubbFish.IoT.Zway.Events;
using BlubbFish.IoT.Zway.Interfaces;
using BlubbFish.Utils;
namespace ZwayBot {
internal class Overtaker {
private ZwayController zw;
private InIReader ini;
private Dictionary<String, Dictionary<String, String>> events = new Dictionary<String, Dictionary<String, String>>();
public delegate void OvertakeValue(Object sender, OvertakerEvent e);
public event OvertakeValue Update;
public Overtaker(ZwayController zw) {
this.zw = zw;
this.ini = InIReader.GetInstance("overtaker.ini");
this.ParseIni();
}
private void ParseIni() {
foreach (String item in this.ini.GetSections()) {
String from = this.ini.GetValue(item, "from");
String[] source = from.Split(':');
this.events.Add(source[0], this.ini.GetSection(item));
String[] addr = source[0].Split('-');
ICommandClass c;
if (addr.Length == 3 || addr.Length == 4) {
Int32 deviceid = Int32.Parse(addr[0]);
Int32 instanceid = Int32.Parse(addr[1]);
Int32 classid = Int32.Parse(addr[2]);
if (addr.Length == 4) {
Int32 subcid = Int32.Parse(addr[3]);
c = this.zw.GetCommandClassSub(deviceid, instanceid, classid, subcid);
} else {
c = this.zw.GetCommandClass(deviceid, instanceid, classid);
}
if (c != null) {
c.Polling = true;
c.Update += this.ChangedEvent;
}
}
}
}
private void ChangedEvent(Object sender, DeviceUpdateEvent e) {
if(Helper.HasInterface(sender, "ICommandClass")) {
if (this.events.ContainsKey(((ICommandClass)sender).Id)) {
this.SetValues(sender, ((ICommandClass)sender).Id, this.events[((ICommandClass)sender).Id]);
}
}
}
private void SetValues(Object sender, String name, Dictionary<String, String> dictionary) {
String from = dictionary["from"];
String[] source = from.Split(':');
if (source.Length != 2) {
return;
}
String source_value;
if (Helper.HasProperty(sender, source[1])) {
source_value = Helper.GetProperty(sender, source[1]).ToString();
} else {
return;
}
if(dictionary.ContainsKey("convert")) {
foreach (String tuple in dictionary["convert"].Split(';')) {
String[] item = tuple.Split('-');
if(source_value == item[0]) {
source_value = item[1];
}
}
}
foreach (String to in dictionary["to"].Split(';')) {
String[] target = to.Split(':');
if(target.Length == 2) {
String[] addr = target[0].Split('-');
if (addr.Length == 3 || addr.Length == 4) {
Int32 deviceid = Int32.Parse(addr[0]);
Int32 instanceid = Int32.Parse(addr[1]);
Int32 classid = Int32.Parse(addr[2]);
ICommandClass c;
if (addr.Length == 4) {
Int32 subcid = Int32.Parse(addr[3]);
c = this.zw.GetCommandClassSub(deviceid, instanceid, classid, subcid);
} else {
c = this.zw.GetCommandClass(deviceid, instanceid, classid);
}
if (c != null) {
String target_value;
if (Helper.HasProperty(c, target[1])) {
target_value = Helper.GetProperty(c, target[1]).ToString();
if (target_value != source_value) {
Helper.SetProperty(c, target[1], source_value);
this.Update?.Invoke(this, new OvertakerEvent(target[0], target[1], source_value));
}
}
}
}
}
}
}
}
}

39
Zway-Bot/Program.cs Normal file
View File

@ -0,0 +1,39 @@
using System;
using BlubbFish.IoT.Zway;
using BlubbFish.Utils;
namespace ZwayBot {
class Program {
static void Main(String[] args) {
ZwayController zw = new ZwayController(InIReader.GetInstance("settings.ini").GetSection("zway"), InIReader.GetInstance("names.ini").GetSection("names"), false);
zw.Update += ZwayDataUpate;
CronJob cron = new CronJob(zw);
cron.Update += Cron_Update;
Overtaker over = new Overtaker(zw);
over.Update += Over_Update;
while (true) {
System.Threading.Thread.Sleep(100);
if (Console.KeyAvailable) {
ConsoleKeyInfo key = Console.ReadKey(false);
if (key.Key == ConsoleKey.Escape) {
break;
}
}
}
cron.Dispose();
zw.Dispose();
}
private static void Over_Update(Object sender, OvertakerEvent e) {
Console.WriteLine("OVERTAKE: " + e.Address + " set " + e.Property + " to " + e.Value);
}
private static void Cron_Update(Object sender, CronEvent e) {
Console.WriteLine("CRON: " + e.Address + " set " + e.Property + " to " + e.Value);
}
private static void ZwayDataUpate(Object sender, BlubbFish.IoT.Zway.Events.DeviceUpdateEvent e) {
Console.WriteLine("-> ZW [" + e.UpdateTime + "]: " + sender.ToString());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("Zway-Bot")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Zway-Bot")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("aef8059f-8aef-45c7-85c4-318c8f797900")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

66
Zway-Bot/Zway-Bot.csproj Normal file
View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AEF8059F-8AEF-45C7-85C4-318C8F797900}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>ZwayBot</RootNamespace>
<AssemblyName>Zway-Bot</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Events.cs" />
<Compile Include="CronJob.cs" />
<Compile Include="Helper.cs" />
<Compile Include="Overtaker.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Utils\Utils\Utils.csproj">
<Project>{fac8ce64-bf13-4ece-8097-aeb5dd060098}</Project>
<Name>Utils</Name>
</ProjectReference>
<ProjectReference Include="..\..\Zway\Zway\Zway.csproj">
<Project>{166258ed-cb3d-43f5-8e8d-3a993b64d022}</Project>
<Name>Zway</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>