init sensormat

This commit is contained in:
joergzeidler 2025-09-23 10:21:23 +02:00
commit e21b483862
44 changed files with 2351 additions and 0 deletions

358
.gitignore vendored Normal file
View File

@ -0,0 +1,358 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
*.7z
*.mde
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
nuget.exe
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
#/Office Line/8.1/MHK81/LBAbfKirstein81 - Kopie.laccdb

View File

@ -0,0 +1,38 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.ESP8266_Gaszaehler.ESP8266_Gaszaehler
// Assembly: ESP8266_Gaszaehler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 4783B34D-C78D-4F6E-946E-4E4DC92855C4
// Assembly location: \\192.168.178.26\Freigabe\ESP8266_Gaszaehler.dll
using Newtonsoft.Json;
using Sensormat.Entities;
using System;
#nullable disable
namespace Sensormat.ESP8266_Gaszaehler
{
public class ESP8266_Gaszaehler : ISensor
{
public override bool Execute()
{
try
{
int id = this.Sensor.ID;
new ResultSet().XMLSerializeData<ResultSet>();
string str = this.HttpRequest(this.Sensor.URL);
if (str != null)
{
this.LastValue = JsonConvert.DeserializeObject<ResultSet>(str).GasMeter;
this.LastValueDate = new DateTime?(DateTime.Now);
return true;
}
}
catch (Exception ex)
{
Console.WriteLine((object)ex);
this.ErrorMsg = ex.Message;
}
return false;
}
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Sensormat\Sensormat.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\Sensormat\References\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.ESP8266_Gaszaehler.ResultSet
// Assembly: ESP8266_Gaszaehler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 4783B34D-C78D-4F6E-946E-4E4DC92855C4
// Assembly location: \\192.168.178.26\Freigabe\ESP8266_Gaszaehler.dll
using System;
#nullable disable
namespace Sensormat.ESP8266_Gaszaehler
{
public class ResultSet
{
public DateTime? StartTime { get; set; }
public string Version { get; set; }
public int WIFIConnectCounter { get; set; }
public string GasMeter { get; set; }
public string ErrorMsg { get; set; }
}
}

View File

@ -0,0 +1,206 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.API.FritzWebAccess.FritzSoapAccess
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using FritzBox.API.FritzWebAccess.SoapTypes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Xml.XPath;
#nullable disable
namespace FritzBox.API.FritzWebAccess
{
public class FritzSoapAccess
{
public Uri BaseAddress { get; set; } = new Uri("https://fritz.box/");
public string Username { get; set; } = "admin";
public string Password { get; set; } = string.Empty;
public int GetHostNumberOfEntries()
{
string elementValue = this.GetElementValue(((WebResponse)this.SendSoapRequest("tr064/upnp/control/hosts", "urn:dslforum-org:service:Hosts:1#GetHostNumberOfEntries")).GetResponseStream(), "NewHostNumberOfEntries");
return elementValue != null ? Convert.ToInt32(elementValue) : -1;
}
public HostInfo GetGenericHostEntryExt(int index)
{
Dictionary<string, string> elementValues = this.GetElementValues(((WebResponse)this.SendSoapRequest("tr064/upnp/control/hosts", "urn:dslforum-org:service:Hosts:1#X_AVM-DE_GetGenericHostEntryExt", new Dictionary<string, string>()
{
{
"NewIndex",
index.ToString()
}
})).GetResponseStream(), (IEnumerable<string>)new string[7]
{
"NewIPAddress",
"NewMACAddress",
"NewActive",
"NewHostName",
"NewInterfaceType",
"NewX_AVM-DE_Port",
"NewX_AVM-DE_Speed"
});
return new HostInfo()
{
IPAddress = elementValues["NewIPAddress"],
MACAddress = elementValues["NewMACAddress"],
IsActive = elementValues["NewActive"] == "1",
HostName = elementValues["NewHostName"],
InterfaceType = elementValues["NewInterfaceType"],
Port = elementValues["NewX_AVM-DE_Port"],
Speed = elementValues["NewX_AVM-DE_Speed"]
};
}
public int GetTotalBytesSent()
{
string elementValue = this.GetElementValue(((WebResponse)this.SendSoapRequest("tr064/upnp/control/wancommonifconfig1", "urn:dslforum-org:service:WANCommonInterfaceConfig:1#GetTotalBytesSent")).GetResponseStream(), "NewTotalBytesSent");
return elementValue == null ? -1 : Convert.ToInt32(elementValue);
}
public int GetTotalBytesReceived()
{
string elementValue = this.GetElementValue(((WebResponse)this.SendSoapRequest("tr064/upnp/control/wancommonifconfig1", "urn:dslforum-org:service:WANCommonInterfaceConfig:1#GetTotalBytesReceived")).GetResponseStream(), "NewTotalBytesReceived");
return elementValue == null ? -1 : Convert.ToInt32(elementValue);
}
public CommonLinkProperties GetCommonLinkProperties()
{
Dictionary<string, string> elementValues = this.GetElementValues(((WebResponse)this.SendSoapRequest("tr064/upnp/control/wancommonifconfig1", "urn:dslforum-org:service:WANCommonInterfaceConfig:1#GetCommonLinkProperties")).GetResponseStream(), (IEnumerable<string>)new string[4]
{
"NewWANAccessType",
"NewLayer1UpstreamMaxBitRate",
"NewLayer1DownstreamMaxBitRate",
"NewPhysicalLinkStatus"
});
return new CommonLinkProperties()
{
AccessType = elementValues["NewWANAccessType"],
MaxUpstreamBitRate = elementValues["NewLayer1UpstreamMaxBitRate"],
MaxDownstreamBitRate = elementValues["NewLayer1DownstreamMaxBitRate"],
Status = elementValues["NewPhysicalLinkStatus"]
};
}
public DslInterfaceInfo GetDslInterfaceInfo()
{
Dictionary<string, string> elementValues = this.GetElementValues(((WebResponse)this.SendSoapRequest("tr064/upnp/control/wandslifconfig1", "urn:dslforum-org:service:WANDSLInterfaceConfig:1#GetInfo")).GetResponseStream(), (IEnumerable<string>)new string[9]
{
"NewStatus",
"NewUpstreamCurrRate",
"NewDownstreamCurrRate",
"NewUpstreamMaxRate",
"NewDownstreamMaxRate",
"NewUpstreamNoiseMargin",
"NewDownstreamNoiseMargin",
"NewUpstreamAttenuation",
"NewDownstreamAttenuation"
});
return new DslInterfaceInfo()
{
Status = elementValues["NewStatus"],
CurrentUpstreamRate = elementValues["NewUpstreamCurrRate"],
CurrentDownstreamRate = elementValues["NewDownstreamCurrRate"],
MaxUpstreamRate = elementValues["NewUpstreamMaxRate"],
MaxDownstreamRate = elementValues["NewDownstreamMaxRate"],
UpstreamNoiseMargin = elementValues["NewUpstreamNoiseMargin"],
DownstreamNoiseMargin = elementValues["NewDownstreamNoiseMargin"],
UpstreamAttenuation = elementValues["NewUpstreamAttenuation"],
DownstreamAttenuation = elementValues["NewDownstreamAttenuation"]
};
}
public string GetExternalIPAddress()
{
return this.GetElementValue(((WebResponse)this.SendSoapRequest("tr064/upnp/control/wanpppconn1", "urn:dslforum-org:service:WANPPPConnection:1#GetExternalIPAddress")).GetResponseStream(), "NewExternalIPAddress");
}
public WirelessLanInfo GetWirelessLanInfo()
{
Dictionary<string, string> elementValues = this.GetElementValues(((WebResponse)this.SendSoapRequest("tr064/upnp/control/wlanconfig1", "urn:dslforum-org:service:WLANConfiguration:1#GetInfo")).GetResponseStream(), (IEnumerable<string>)new string[4]
{
"NewEnable",
"NewStatus",
"NewChannel",
"NewSSID"
});
return new WirelessLanInfo()
{
IsEnabled = elementValues["NewEnable"] == "1",
Status = elementValues["NewStatus"],
Channel = elementValues["NewChannel"],
SSID = elementValues["NewSSID"]
};
}
public void SetWirelessLan(bool enable)
{
this.SendSoapRequest("tr064/upnp/control/wlanconfig1", "urn:dslforum-org:service:WLANConfiguration:1#SetEnable", new Dictionary<string, string>()
{
{
"NewEnable",
enable ? "1" : "0"
}
});
}
private HttpWebResponse SendSoapRequest(
string relativeUrl,
string soapAction,
Dictionary<string, string> soapActionParameters = null)
{
HttpWebRequest httpWebRequest = WebRequest.Create(new Uri(this.BaseAddress, relativeUrl)) as HttpWebRequest;
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "text/xml; charset=utf-8";
httpWebRequest.Headers.Add("SOAPAction", soapAction);
httpWebRequest.Credentials = (ICredentials)new NetworkCredential(this.Username, this.Password);
string[] strArray = soapAction.Split('#', StringSplitOptions.None);
StreamWriter streamWriter = new StreamWriter(((WebRequest)httpWebRequest).GetRequestStream(), Encoding.ASCII);
((TextWriter)streamWriter).WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
((TextWriter)streamWriter).WriteLine("<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">");
((TextWriter)streamWriter).WriteLine("<s:Body>");
if (soapActionParameters == null)
{
((TextWriter)streamWriter).WriteLine("<{1} xmlns=\"{0}\"/>", (object)strArray[0], (object)strArray[1]);
}
else
{
((TextWriter)streamWriter).WriteLine("<{1} xmlns=\"{0}\">", (object)strArray[0], (object)strArray[1]);
foreach (string key in soapActionParameters.Keys)
((TextWriter)streamWriter).WriteLine("<{0}>{1}</{0}>", (object)key, (object)soapActionParameters[key]);
((TextWriter)streamWriter).WriteLine("</{0}>", (object)strArray[1]);
}
((TextWriter)streamWriter).WriteLine("</s:Body>");
((TextWriter)streamWriter).WriteLine("</s:Envelope>");
((TextWriter)streamWriter).Close();
return httpWebRequest.GetResponse() as HttpWebResponse;
}
private string GetElementValue(Stream xmlStream, string elementName)
{
return ((XPathItem)new XPathDocument(xmlStream).CreateNavigator().SelectSingleNode("//" + elementName))?.Value;
}
private Dictionary<string, string> GetElementValues(
Stream xmlStream,
IEnumerable<string> elementNames)
{
Dictionary<string, string> elementValues = new Dictionary<string, string>();
XPathNavigator navigator = new XPathDocument(xmlStream).CreateNavigator();
foreach (string elementName in elementNames)
{
XPathNavigator xpathNavigator = navigator.SelectSingleNode("//" + elementName);
if (xpathNavigator != null)
elementValues[elementName] = ((XPathItem)xpathNavigator).Value;
}
return elementValues;
}
}
}

View File

@ -0,0 +1,87 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.API.FritzWebAccess.FritzWebAccess
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
#nullable disable
namespace FritzBox.API.FritzWebAccess
{
public class FritzWebAccess
{
public Uri Address { get; set; } = new Uri("http://fritz.box/");
public Uri SoapAddress => new Uri(this.Address.Scheme + "://" + this.Address.Host + ":49000/");
public string SessionId { get; private set; }
public bool IsAuthenticated
{
get => !string.IsNullOrEmpty(this.SessionId) && this.SessionId != "0000000000000000";
}
public FritzWebAccess()
{
}
public FritzWebAccess(string username, string password) => this.LogIn(username, password);
public void LogIn(string password) => this.LogIn(string.Empty, password);
public void LogIn(string username, string password)
{
Uri uri = new Uri(this.Address, "login_sid.lua");
XDocument doc = XDocument.Load(uri.AbsoluteUri);
this.SessionId = this.GetValue(doc, "SID");
if (this.IsAuthenticated)
return;
string challenge = this.GetValue(doc, "Challenge");
this.SessionId = this.GetValue(XDocument.Load(string.Format("{0}?username={1}&response={2}", (object)uri.AbsoluteUri, (object)username, (object)this.GetAuthResponse(challenge, password))), "SID");
}
private string GetValue(XDocument doc, string elementName)
{
return (doc.FirstNode as XElement).Element((XName)elementName).Value;
}
private string GetAuthResponse(string challenge, string password)
{
return challenge + "-" + this.GetMD5Hash(challenge + "-" + password);
}
private string GetMD5Hash(string input)
{
byte[] hash = MD5.Create().ComputeHash(Encoding.Unicode.GetBytes(input));
StringBuilder stringBuilder = new StringBuilder();
for (int index = 0; index < hash.Length; ++index)
stringBuilder.Append(hash[index].ToString("x2"));
return stringBuilder.ToString();
}
public string GetWebContent(string relativeUrl, string parameter = "")
{
return this.GetContent(this.Address, relativeUrl, parameter);
}
public string GetSoapContent(string relativeUrl, string parameter = "")
{
return this.GetContent(this.SoapAddress, relativeUrl, parameter);
}
public string GetContent(Uri baseAddress, string relativeUrl, string parameter = "")
{
using (HttpWebResponse response = (WebRequest.Create(new Uri(baseAddress, relativeUrl + "?sid=" + this.SessionId + parameter)) as HttpWebRequest).GetResponse() as HttpWebResponse)
{
using (StreamReader streamReader = new StreamReader(((WebResponse)response).GetResponseStream()))
return ((TextReader)streamReader).ReadToEnd();
}
}
}
}

View File

@ -0,0 +1,25 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.API.FritzWebAccess.SoapTypes.CommonLinkProperties
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
#nullable disable
namespace FritzBox.API.FritzWebAccess.SoapTypes
{
public class CommonLinkProperties
{
public string AccessType { get; set; }
public string MaxUpstreamBitRate { get; set; }
public string MaxDownstreamBitRate { get; set; }
public string Status { get; set; }
public override string ToString()
{
return string.Format("AccessType: {0}, MaxUpstreamBitRate: {1}, MaxDownstreamBitRate: {2}, Status: {3}", (object)this.AccessType, (object)this.MaxUpstreamBitRate, (object)this.MaxDownstreamBitRate, (object)this.Status);
}
}
}

View File

@ -0,0 +1,35 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.API.FritzWebAccess.SoapTypes.DslInterfaceInfo
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
#nullable disable
namespace FritzBox.API.FritzWebAccess.SoapTypes
{
public class DslInterfaceInfo
{
public string Status { get; set; }
public string CurrentUpstreamRate { get; set; }
public string CurrentDownstreamRate { get; set; }
public string MaxUpstreamRate { get; set; }
public string MaxDownstreamRate { get; set; }
public string UpstreamNoiseMargin { get; set; }
public string DownstreamNoiseMargin { get; set; }
public string UpstreamAttenuation { get; set; }
public string DownstreamAttenuation { get; set; }
public override string ToString()
{
return string.Format("Status: {0}, Up/Down- RateCurrent: {1}/{2}, RateMax: {3}/{4}, NoiseMargin: {5}/{6}, Attenuation: {7}/{8}", (object)this.Status, (object)this.CurrentUpstreamRate, (object)this.CurrentDownstreamRate, (object)this.MaxUpstreamRate, (object)this.MaxDownstreamRate, (object)this.UpstreamNoiseMargin, (object)this.DownstreamNoiseMargin, (object)this.UpstreamAttenuation, (object)this.DownstreamAttenuation);
}
}
}

View File

@ -0,0 +1,31 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.API.FritzWebAccess.SoapTypes.HostInfo
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
#nullable disable
namespace FritzBox.API.FritzWebAccess.SoapTypes
{
public class HostInfo
{
public string IPAddress { get; set; }
public string MACAddress { get; set; }
public bool IsActive { get; set; }
public string HostName { get; set; }
public string InterfaceType { get; set; }
public string Port { get; set; }
public string Speed { get; set; }
public override string ToString()
{
return string.Format("IP: {0}, MAC: {1}, IsActive: {2}, HostName: {3}, Interface: {4}, Port: {5}, Speed: {6}", (object)this.IPAddress, (object)this.MACAddress, (object)this.IsActive, (object)this.HostName, (object)this.InterfaceType, (object)this.Port, (object)this.Speed);
}
}
}

View File

@ -0,0 +1,25 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.API.FritzWebAccess.SoapTypes.WirelessLanInfo
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
#nullable disable
namespace FritzBox.API.FritzWebAccess.SoapTypes
{
public class WirelessLanInfo
{
public bool IsEnabled { get; set; }
public string Status { get; set; }
public string Channel { get; set; }
public string SSID { get; set; }
public override string ToString()
{
return string.Format("IsEnabled: {0}, Status: {1}, Channel: {2}, SSID: {3}", (object)this.IsEnabled, (object)this.Status, (object)this.Channel, (object)this.SSID);
}
}
}

View File

@ -0,0 +1,20 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.Config
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
#nullable disable
namespace FritzBox
{
public class Config
{
public string UserName { get; set; }
public string Password { get; set; }
public string AIN { get; set; }
public string Property { get; set; }
}
}

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Sensormat\Sensormat.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,55 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.GetDeviceInfoResponse
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using System.Diagnostics;
using System.Xml.Serialization;
#nullable disable
namespace FritzBox
{
[XmlRoot(ElementName = "device")]
public class GetDeviceInfoResponse
{
[XmlElement(ElementName = "present")]
public int Present { get; set; }
[XmlElement(ElementName = "txbusy")]
public int Txbusy { get; set; }
[XmlElement(ElementName = "name")]
public string Name { get; set; }
[XmlElement(ElementName = "switch")]
public Switch Switch { get; set; }
[XmlElement(ElementName = "simpleonoff")]
public Simpleonoff Simpleonoff { get; set; }
[XmlElement(ElementName = "powermeter")]
public Powermeter Powermeter { get; set; }
[XmlElement(ElementName = "temperature")]
public Temperature Temperature { get; set; }
[XmlAttribute(AttributeName = "identifier")]
public string Identifier { get; set; }
[XmlAttribute(AttributeName = "id")]
public int Id { get; set; }
[XmlAttribute(AttributeName = "functionbitmask")]
public int Functionbitmask { get; set; }
[XmlAttribute(AttributeName = "fwversion")]
public string Fwversion { get; set; }
[XmlAttribute(AttributeName = "manufacturer")]
public string Manufacturer { get; set; }
[XmlAttribute(AttributeName = "productname")]
public string Productname { get; set; }
}
}

View File

@ -0,0 +1,60 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.GetValue
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using Sensormat;
using Sensormat.Entities;
using System;
#nullable disable
namespace FritzBox
{
public class GetValue : ISensor
{
private Config cfg;
public override bool Execute()
{
try
{
this.cfg = this.getConfiguration<Config>();
string webContent = new FritzBox.API.FritzWebAccess.FritzWebAccess(this.cfg.UserName, this.cfg.Password)
{
Address = new Uri(this.Sensor.URL)
}.GetWebContent("webservices/homeautoswitch.lua", "&ain=" + this.cfg.AIN + "&switchcmd=getdeviceinfos");
if (webContent != null)
{
GetDeviceInfoResponse deviceInfoResponse = webContent.XMLDeserializeData<GetDeviceInfoResponse>();
if (deviceInfoResponse != null)
{
this.LastValueDate = new DateTime?(DateTime.Now);
switch (this.cfg.Property?.ToLower())
{
case "power":
this.LastValue = deviceInfoResponse.Powermeter?.Power.ToString();
break;
case "energy":
this.LastValue = deviceInfoResponse.Powermeter?.Energy.ToString();
break;
default:
this.LastValue = "property " + this.cfg.Property + " unknown";
break;
}
return true;
}
this.ErrorMsg = "empty result";
}
else
this.ErrorMsg = "response is empty";
}
catch (Exception ex)
{
Console.WriteLine((object)ex);
this.ErrorMsg = ex.Message;
}
return false;
}
}
}

View File

@ -0,0 +1,24 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.Powermeter
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using System.Xml.Serialization;
#nullable disable
namespace FritzBox
{
[XmlRoot(ElementName = "powermeter")]
public class Powermeter
{
[XmlElement(ElementName = "voltage")]
public int Voltage { get; set; }
[XmlElement(ElementName = "power")]
public int Power { get; set; }
[XmlElement(ElementName = "energy")]
public int Energy { get; set; }
}
}

View File

@ -0,0 +1,18 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.Simpleonoff
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using System.Xml.Serialization;
#nullable disable
namespace FritzBox
{
[XmlRoot(ElementName = "simpleonoff")]
public class Simpleonoff
{
[XmlElement(ElementName = "state")]
public int State { get; set; }
}
}

View File

@ -0,0 +1,27 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.Switch
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using System.Xml.Serialization;
#nullable disable
namespace FritzBox
{
[XmlRoot(ElementName = "switch")]
public class Switch
{
[XmlElement(ElementName = "state")]
public int State { get; set; }
[XmlElement(ElementName = "mode")]
public string Mode { get; set; }
[XmlElement(ElementName = "lock")]
public int Lock { get; set; }
[XmlElement(ElementName = "devicelock")]
public int Devicelock { get; set; }
}
}

View File

@ -0,0 +1,21 @@
// Decompiled with JetBrains decompiler
// Type: FritzBox.Temperature
// Assembly: FritzBox, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: DC9FD63C-0A96-43D7-A76E-0506FEB07200
// Assembly location: \\192.168.178.26\Freigabe\FritzBox.dll
using System.Xml.Serialization;
#nullable disable
namespace FritzBox
{
[XmlRoot(ElementName = "temperature")]
public class Temperature
{
[XmlElement(ElementName = "celsius")]
public int Celsius { get; set; }
[XmlElement(ElementName = "offset")]
public int Offset { get; set; }
}
}

View File

@ -0,0 +1,85 @@
DELIMITER $$
DROP PROCEDURE IF EXISTS spSensorCalculate$$
CREATE DEFINER=`root`@`%` PROCEDURE `spSensorCalculate`()
NOT DETERMINISTIC
SQL SECURITY DEFINER
BEGIN
DECLARE dfrom DATETIME;
SET dfrom = NOW() - INTERVAL 14 DAY;
/* Stundenwerte erzeugen / aktualisieren (ohne CTE) */
INSERT INTO tblSensorDataStunde
(SensorID, Datum, StartValue, EndValue, ValueMIN, ValueMAX, ValueAVG)
SELECT
sd.SensorID,
DATE_FORMAT(sd.ValueDate, '%Y-%m-%d %H:00:00') AS Datum,
CASE s.Berechnung
WHEN 1 THEN MIN(sd.Value)
WHEN 2 THEN MAX(sd.Value)
END AS StartValue,
NULL AS EndValue,
MIN(sd.Value) AS ValueMIN,
MAX(sd.Value) AS ValueMAX,
AVG(sd.Value) AS ValueAVG
FROM tblSensoren s
JOIN tblSensorData sd ON s.ID = sd.SensorID
WHERE sd.Value IS NOT NULL
AND sd.ValueDate >= dfrom
AND s.Berechnung <> 0
GROUP BY sd.SensorID, DATE_FORMAT(sd.ValueDate, '%Y-%m-%d %H:00:00')
ON DUPLICATE KEY UPDATE
StartValue = VALUES(StartValue),
EndValue = NULL,
ValueMIN = VALUES(ValueMIN),
ValueMAX = VALUES(ValueMAX),
ValueAVG = VALUES(ValueAVG);
/* --- 1093-sicher: NextStart in TEMP-Tabelle berechnen --- */
DROP TEMPORARY TABLE IF EXISTS tmp_next;
/* Variante ohne Window-Funktionen (läuft auch auf älteren Versionen):
Wir sortieren pro Sensor DESC nach Datum, dann ist "prev_start" die nächste Stunde. */
CREATE TEMPORARY TABLE tmp_next
AS
SELECT SensorID, Datum, NextStart
FROM (
SELECT
x.SensorID,
x.Datum,
/* beim Abstieg ist die "vorherige" StartValue die nächste in der Zukunft */
CASE WHEN @cur_sid = x.SensorID THEN @prev_start ELSE NULL END AS NextStart,
/* Hilfszuweisungen für den nächsten Datensatz */
@prev_start := x.StartValue AS _set_prev,
@cur_sid := x.SensorID AS _set_sid
FROM (
SELECT SensorID, Datum, StartValue
FROM tblSensorDataStunde
WHERE Datum >= dfrom
ORDER BY SensorID, Datum DESC
) x
/* Variablen initialisieren */
JOIN (SELECT @cur_sid := NULL, @prev_start := NULL) vars
) z;
/* Jetzt gefahrlos updaten, weil wir aus tmp_next lesen, nicht aus der Zieltabelle */
UPDATE tblSensorDataStunde t
JOIN tmp_next n
ON n.SensorID = t.SensorID AND n.Datum = t.Datum
SET t.EndValue = n.NextStart
WHERE t.Datum >= dfrom
AND t.EndValue IS NULL
AND n.NextStart IS NOT NULL;
DROP TEMPORARY TABLE IF EXISTS tmp_next;
END$$
DELIMITER ;
CALL spSensorCalculate;

43
Sensormat/Sensormat.sln Normal file
View File

@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36414.22 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sensormat", "Sensormat\Sensormat.csproj", "{AD805DAC-A72F-4785-9CAD-4DEE29D7B647}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzBox", "FritzBox\FritzBox.csproj", "{73C49A84-293E-442C-8198-B3CBE2E8CFF8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ESP8266_Gaszaehler", "ESP8266_Gaszaehler\ESP8266_Gaszaehler.csproj", "{CEB7D1F4-BB04-44D1-9CE1-0EF04D3EE958}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shelly", "Shelly\Shelly.csproj", "{A63DCF66-60EF-4256-8609-6C423F484EFF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AD805DAC-A72F-4785-9CAD-4DEE29D7B647}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AD805DAC-A72F-4785-9CAD-4DEE29D7B647}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AD805DAC-A72F-4785-9CAD-4DEE29D7B647}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AD805DAC-A72F-4785-9CAD-4DEE29D7B647}.Release|Any CPU.Build.0 = Release|Any CPU
{73C49A84-293E-442C-8198-B3CBE2E8CFF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73C49A84-293E-442C-8198-B3CBE2E8CFF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73C49A84-293E-442C-8198-B3CBE2E8CFF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73C49A84-293E-442C-8198-B3CBE2E8CFF8}.Release|Any CPU.Build.0 = Release|Any CPU
{CEB7D1F4-BB04-44D1-9CE1-0EF04D3EE958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CEB7D1F4-BB04-44D1-9CE1-0EF04D3EE958}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CEB7D1F4-BB04-44D1-9CE1-0EF04D3EE958}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CEB7D1F4-BB04-44D1-9CE1-0EF04D3EE958}.Release|Any CPU.Build.0 = Release|Any CPU
{A63DCF66-60EF-4256-8609-6C423F484EFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A63DCF66-60EF-4256-8609-6C423F484EFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A63DCF66-60EF-4256-8609-6C423F484EFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A63DCF66-60EF-4256-8609-6C423F484EFF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B15582B7-B501-4507-8D60-4312FE32CC79}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.Json;
namespace Sensormat
{
public class Config
{
private const string ConfigName = "cfg/config.json";
// Beispiel-Properties (passen an deine JSON-Struktur an!)
public string MainUrl { get; set; } = @"http://*:810/";
public string MYSQL_Server { get; set; } = "docker-1";
public string MYSQL_User { get; set; } = "ESP8266_Gaszaehler";
public string MYSQL_Password { get; set; } = "gFKWa8lFJwFUcBysn4HI";
public string MYSQL_Database { get; set; } = "zeidlerme";
public static Config Load()
{
string basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
?? AppContext.BaseDirectory;
string configPath = Path.Combine(basePath, ConfigName);
var options = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true
};
// Datei fehlt → Standardobjekt erzeugen und abspeichern
if (!File.Exists(configPath))
{
var defaultConfig = new Config();
string json = JsonSerializer.Serialize(defaultConfig, options);
File.WriteAllText(configPath, json);
Console.WriteLine($"Config created {configPath}");
return defaultConfig;
}
// Datei vorhanden → einlesen
string content = File.ReadAllText(configPath);
var cfg = JsonSerializer.Deserialize<Config>(content, options);
if (cfg == null)
throw new InvalidOperationException("Konfigurationsdatei konnte nicht geladen werden.");
Console.WriteLine($"config loaded {configPath}");
return cfg;
}
}
}

View File

@ -0,0 +1,6 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1
COPY ./bin/Release/netcoreapp3.1/. /app
WORKDIR /app
EXPOSE 810/tcp
ENV TZ=Europe/Berlin
CMD ["sh", "-c", "dotnet Sensormat.dll $Config" ]

View File

@ -0,0 +1,100 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.Entities.ISensor
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using MySqlConnector;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text.Json.Serialization;
#nullable disable
namespace Sensormat.Entities
{
public class ISensor
{
private Sensoren _sensor;
public ISensor()
{
}
public ISensor(int SensorID) => this.SensorID = SensorID;
public MySqlConnection connection { get; set; }
public string ErrorMsg { get; set; }
public string LastValue { get; set; }
public DateTime? LastValueDate { get; set; }
public virtual int SensorID { get; set; }
public virtual bool Execute() => false;
public Sensoren Sensor
{
get
{
if (this.SensorID == 0)
throw new Exception("SensorID = 0");
if (this._sensor == null)
{
using (MySqlCommand command = this.connection.CreateCommand())
{
command.CommandText = "SELECT * FROM tblSensoren WHERE ID = @SensorID";
command.Parameters.AddWithValue("SensorID", (object)this.SensorID);
using (MySqlDataReader rd = command.ExecuteReader())
{
if (rd.HasRows)
{
rd.Read();
this._sensor = rd.ParseObject<Sensoren>();
}
}
}
}
return this._sensor;
}
}
public T getConfiguration<T>()
{
if (this.Sensor != null)
{
if (!string.IsNullOrEmpty(this.Sensor.config))
{
try
{
return JsonConvert.DeserializeObject<T>(this.Sensor.config);
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, string.Format("{0}", (object)this.Sensor.ID), (object)ex);
return default(T);
}
}
}
return default(T);
}
public string HttpRequest(string URL)
{
WebRequest webRequest = WebRequest.Create(URL);
webRequest.Method = "GET";
using (WebResponse response = webRequest.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader streamReader = new StreamReader(responseStream))
return ((TextReader)streamReader).ReadToEnd();
}
}
}
}
}

View File

@ -0,0 +1,20 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.Entities.SensorData
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using System;
#nullable disable
namespace Sensormat.Entities
{
public class SensorData
{
public int SensorID { get; set; }
public Decimal Value { get; set; }
public DateTime? ValueDate { get; set; }
}
}

View File

@ -0,0 +1,50 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.Entities.Sensoren
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using System;
#nullable disable
namespace Sensormat.Entities
{
public class Sensoren
{
public int ID { get; set; }
public string Description { get; set; }
public string URL { get; set; }
public string LastValue { get; set; }
public DateTime? LastCall { get; set; }
public string ErrorMsg { get; set; }
public int Intervall { get; set; }
public string Assembly { get; set; }
public string TypeName { get; set; }
public int Aktiv { get; set; }
public DateTime? LastValueDate { get; set; }
public Sensoren.CheckChangedMethods CheckChanged { get; set; }
public string Passphrase { get; set; }
public string config { get; set; }
public enum CheckChangedMethods
{
none,
value,
valuedate,
valueorvaluedate,
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.IO;
namespace Sensormat
{
public class EventLog
{
public static void Write(string Source, string Message, params object[] param)
{
try
{
if (!Directory.Exists("LOG"))
Directory.CreateDirectory("LOG");
string path = "LOG/" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
string contents = Environment.NewLine + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + Source + Environment.NewLine + " " + Message;
if (param != null)
{
foreach (object obj in param)
{
if (obj != null)
{
if (obj.GetType() == typeof(string))
contents += string.Format("{0}{1}", obj, (object)Environment.NewLine);
if (obj.GetType() == typeof(Exception))
contents += string.Format("{0}{1} {2} {3}{4}", obj, (object)((Exception)obj).Message, (object)((Exception)obj).Message, (object)((Exception)obj).InnerException, (object)Environment.NewLine);
}
}
}
Console.WriteLine(contents);
File.AppendAllText(path, contents);
}
catch (Exception ex)
{
Console.WriteLine("Logging Error: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + ex.Message);
}
}
}
}

View File

@ -0,0 +1,89 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.HttpServer
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;
#nullable disable
namespace Sensormat
{
public class HttpServer
{
public HttpListener listener;
private string URL;
public HttpServer.HttpServerIncomingRequestCallBack httpServerIncomingRequest { get; set; }
public async Task HandleIncomingConnections()
{
bool runServer = true;
while (runServer)
{
HttpListenerContext contextAsync = await this.listener.GetContextAsync();
HttpListenerRequest request = contextAsync.Request;
HttpListenerResponse resp = contextAsync.Response;
Console.WriteLine(request.Url.ToString());
Console.WriteLine(request.HttpMethod);
Console.WriteLine(request.UserHostName);
Console.WriteLine(request.UserAgent);
Console.WriteLine();
HttpServerIncomingRequestCallBackParameter e = new HttpServerIncomingRequestCallBackParameter()
{
StatusCode = 200,
StatusDescription = "",
Result = "",
URL = this.URL,
Request = request,
AbsolutePath = request.Url.AbsolutePath.Trim('/')
};
if (request.QueryString != null)
{
foreach (string allKey in request.QueryString.AllKeys)
e.Query.Add(allKey, request.QueryString[allKey]);
}
if (this.httpServerIncomingRequest != null)
this.httpServerIncomingRequest(e);
byte[] bytes = Encoding.UTF8.GetBytes(e.Result);
resp.ContentType = "text/html";
resp.ContentEncoding = Encoding.UTF8;
resp.ContentLength64 = (long)bytes.Length;
resp.StatusCode = e.StatusCode;
resp.StatusDescription = e.StatusDescription;
await resp.OutputStream.WriteAsync(bytes, 0, bytes.Length);
resp.Close();
resp = (HttpListenerResponse)null;
}
}
private string getValue(string ID) => "OK " + ID;
private string setValue(string ID, string Parameter) => "setValue " + ID + " " + Parameter;
public HttpServer(string url)
{
this.listener = new HttpListener();
this.listener.Prefixes.Add(url);
this.listener.Start();
Console.WriteLine("Listening for connections on {0}", (object)url);
this.URL = url;
this.HandleIncomingConnections();
}
public bool Test() => !string.IsNullOrEmpty(new WebClient().DownloadString(this.URL));
public void Release()
{
if (this.listener == null)
return;
this.listener.Close();
}
public delegate void HttpServerIncomingRequestCallBack(
HttpServerIncomingRequestCallBackParameter e);
}
}

View File

@ -0,0 +1,29 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.HttpServerIncomingRequestCallBackParameter
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using System.Collections.Generic;
using System.Net;
#nullable disable
namespace Sensormat
{
public class HttpServerIncomingRequestCallBackParameter
{
public string Result { get; set; }
public string StatusDescription { get; set; }
public int StatusCode { get; set; }
public string URL { get; set; }
public HttpListenerRequest Request { get; set; }
public string AbsolutePath { get; set; }
public Dictionary<string, string> Query { get; set; } = new Dictionary<string, string>();
}
}

View File

@ -0,0 +1,295 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.Manager
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using MySqlConnector;
using Sensormat.Entities;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Threading;
#nullable disable
namespace Sensormat
{
public class Manager
{
private Config config;
private MySqlConnection connection;
private static Semaphore semaphore = new Semaphore(1, 1);
private HttpServer httpServer;
private DateTime lastCalculate;
public string HelpData = "<!DOCTYPE>\r\n <html>\r\n <head>\r\n <title>Sensormat WebInterface</title>\r\n </head>\r\n <body>\r\n <p>Help</p>\r\n <p>GetValue</p> [URL]/GetValue?Passphrase={Passphrase}&ID={SensorID}\r\n <p>SetValue</p> \r\n [URL]/SetValue?Passphrase={Passphrase}&ID={SensorID}&Value={Value}&[ValueDate={ValueDate}]\r\n </body>\r\n </html>";
private bool UpdateSensor(Sensoren sensor)
{
try
{
using (MySqlCommand command = this.connection.CreateCommand())
{
command.CommandText = "UPDATE tblSensoren SET LastValue = @LastValue, LastValueDate = @LastValueDate, LastCall = @LastCall, ErrorMsg = @ErrorMsg WHERE ID = @SensorID";
command.Parameters.AddWithValue("LastValue", (object)sensor.LastValue);
command.Parameters.AddWithValue("LastValueDate", (object)sensor.LastValueDate);
command.Parameters.AddWithValue("LastCall", (object)sensor.LastCall);
command.Parameters.AddWithValue("ErrorMsg", (object)sensor.ErrorMsg);
command.Parameters.AddWithValue("SensorID", (object)sensor.ID);
return command.ExecuteNonQuery() == 1;
}
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, ex.Message, (object)string.Format("SensorID={0}", (object)sensor.ID), (object)ex);
}
return false;
}
private bool UpdateSensorData(Sensoren sensor)
{
try
{
using (MySqlCommand command = this.connection.CreateCommand())
{
command.CommandText = "INSERT INTO tblSensorData (SensorID, RawValue, ValueDate,CD) VALUES (@SensorID, @RawValue, @ValueDate, @Datum)";
command.Parameters.AddWithValue("SensorID", (object)sensor.ID);
command.Parameters.AddWithValue("RawValue", (object)sensor.LastValue);
command.Parameters.AddWithValue("ValueDate", (object)sensor.LastValueDate);
command.Parameters.AddWithValue("Datum", (object)DateTime.Now);
return command.ExecuteNonQuery() == 1;
}
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, ex.Message, (object)string.Format("SensorID={0}", (object)sensor.ID), (object)ex);
sensor.ErrorMsg = string.Format("{0} SensorID={1} {2} {3}", (object)((MemberInfo)MethodBase.GetCurrentMethod()).Name, (object)sensor.ID, (object)ex.Message, (object)ex);
}
return false;
}
private void HandleSensor(ISensor SensorEntity)
{
try
{
if (SensorEntity == null)
return;
if (SensorEntity.Sensor.LastCall.HasValue)
{
DateTime now = DateTime.Now;
DateTime? lastCall = SensorEntity.Sensor.LastCall;
if ((lastCall.HasValue ? new TimeSpan?(now - lastCall.GetValueOrDefault()) : new TimeSpan?()).Value.TotalMinutes < (double)SensorEntity.Sensor.Intervall)
return;
}
SensorEntity.Execute();
this.SetValue(SensorEntity, SensorEntity.LastValue, (string)null);
SensorEntity.Sensor.ErrorMsg = "";
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, ex.Message, (object)string.Format("SensorID={0}", (object)SensorEntity.SensorID), (object)ex);
Console.WriteLine((object)ex);
}
}
private ISensor GetSensor(int SensorID, string Passphrase)
{
ISensor isensor = new ISensor(SensorID);
isensor.connection = this.connection;
return isensor.Sensor == null || isensor.Sensor.Passphrase != Passphrase ? (ISensor)null : isensor;
}
private bool GetValue(int SensorID, out string Result)
{
Result = "";
ISensor isensor = new ISensor(SensorID);
isensor.connection = this.connection;
if (isensor.Sensor == null)
return false;
Result = isensor.Sensor.LastValue;
return true;
}
private bool SetValue(ISensor SensorEntity, string Value, string ValueDateString)
{
DateTime result;
if (!DateTime.TryParse(ValueDateString, out result))
result = DateTime.Now;
if (SensorEntity.Sensor.CheckChanged != Sensoren.CheckChangedMethods.none && (SensorEntity.Sensor.CheckChanged != Sensoren.CheckChangedMethods.value || !(SensorEntity.Sensor.LastValue != Value) && SensorEntity.Sensor.LastValue != null))
{
DateTime? lastValueDate;
if (SensorEntity.Sensor.CheckChanged == Sensoren.CheckChangedMethods.valuedate)
{
lastValueDate = SensorEntity.Sensor.LastValueDate;
DateTime dateTime = result;
if ((lastValueDate.HasValue ? (lastValueDate.HasValue ? (lastValueDate.GetValueOrDefault() != dateTime ? 1 : 0) : 0) : 1) == 0)
{
lastValueDate = SensorEntity.Sensor.LastValueDate;
if (!lastValueDate.HasValue)
goto label_9;
}
else
goto label_9;
}
if (SensorEntity.Sensor.CheckChanged == Sensoren.CheckChangedMethods.valueorvaluedate)
{
lastValueDate = SensorEntity.Sensor.LastValueDate;
DateTime dateTime = result;
if ((lastValueDate.HasValue ? (lastValueDate.HasValue ? (lastValueDate.GetValueOrDefault() != dateTime ? 1 : 0) : 0) : 1) == 0)
{
lastValueDate = SensorEntity.Sensor.LastValueDate;
if (lastValueDate.HasValue && !(SensorEntity.Sensor.LastValue != Value) && SensorEntity.Sensor.LastValue != null)
goto label_10;
}
}
else
goto label_10;
}
label_9:
SensorEntity.Sensor.LastValue = Value;
SensorEntity.Sensor.LastValueDate = new DateTime?(result);
this.UpdateSensorData(SensorEntity.Sensor);
label_10:
SensorEntity.Sensor.LastCall = new DateTime?(DateTime.Now);
SensorEntity.Sensor.ErrorMsg = SensorEntity.ErrorMsg;
this.UpdateSensor(SensorEntity.Sensor);
return true;
}
private void CheckConnection()
{
if (this.connection.State == ConnectionState.Connecting)
{
do
{
Thread.Sleep(1000);
Console.Write(".");
}
while (this.connection.State == ConnectionState.Connecting);
}
if (this.connection.State == ConnectionState.Open)
return;
this.connection.Open();
}
private void CalculateData()
{
try
{
if ((DateTime.Now - this.lastCalculate).TotalMinutes < 10.0)
return;
this.connection.CallCalculate();
this.lastCalculate = DateTime.Now;
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, ex.Message, (object)ex);
}
}
public void Run()
{
try
{
this.config = Config.Load();
this.httpServer = new HttpServer(config.MainUrl);
this.httpServer.httpServerIncomingRequest += new HttpServer.HttpServerIncomingRequestCallBack(this.httpServerIncomingRequest);
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, "cant't start server " + ex.Message, (object)ex);
}
this.connection = new MySqlConnection($"Server={config.MYSQL_Server};User ID={config.MYSQL_User};Password={config.MYSQL_Password};Database={config.MYSQL_Database}");
while (true)
{
try
{
this.CheckConnection();
Manager.semaphore.WaitOne();
foreach (Sensoren sensor in this.connection.GetSensoren().ToArray<Sensoren>())
{
try
{
if (string.IsNullOrWhiteSpace(sensor.Assembly))
throw new Exception("Assemblyfile " + sensor.Assembly + " not found");
Type type = Assembly.LoadFrom(sensor.Assembly).GetType(sensor.TypeName);
ISensor SensorEntity = !(type == (Type)null) ? Activator.CreateInstance(type) as ISensor : throw new Exception("type " + sensor.TypeName + " not found");
SensorEntity.SensorID = sensor.ID;
SensorEntity.connection = this.connection;
if (SensorEntity == null)
throw new Exception(string.Format("can't create Instance {0}", (object)type));
this.HandleSensor(SensorEntity);
}
catch (Exception ex)
{
sensor.ErrorMsg = string.Format("{0} {1} {2} {3}", (object)ex.Message, (object)ex.Source, (object)ex.StackTrace, (object)ex.InnerException);
this.UpdateSensor(sensor);
}
}
this.CalculateData();
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, ex.Message, (object)ex);
}
finally
{
Manager.semaphore.Release();
Thread.Sleep(60000);
}
}
}
private void httpServerIncomingRequest(HttpServerIncomingRequestCallBackParameter e)
{
try
{
Manager.semaphore.WaitOne();
string str1 = this.HelpData.Replace("[URL]", e.URL);
string[] strArray = e.AbsolutePath.Trim('/').Split('/', StringSplitOptions.None);
KeyValuePair<string, string> keyValuePair = e.Query.FirstOrDefault<KeyValuePair<string, string>>((Func<KeyValuePair<string, string>, bool>)(f => f.Key.ToLower() == "id"));
string s = keyValuePair.Value;
keyValuePair = e.Query.FirstOrDefault<KeyValuePair<string, string>>((Func<KeyValuePair<string, string>, bool>)(f => f.Key.ToLower() == "value"));
string str2 = keyValuePair.Value;
keyValuePair = e.Query.FirstOrDefault<KeyValuePair<string, string>>((Func<KeyValuePair<string, string>, bool>)(f => f.Key.ToLower() == "valuedate"));
string ValueDateString = keyValuePair.Value;
keyValuePair = e.Query.FirstOrDefault<KeyValuePair<string, string>>((Func<KeyValuePair<string, string>, bool>)(f => f.Key.ToLower() == "passphrase"));
string Passphrase = keyValuePair.Value;
int result;
if (strArray.Length == 1 && int.TryParse(s, out result) && result > 0)
{
ISensor sensor = this.GetSensor(result, Passphrase);
if (sensor == null)
{
e.StatusCode = 500;
return;
}
switch (strArray[0].ToLower())
{
case "getvalue":
str1 = sensor.Sensor.LastValue;
break;
case "setvalue":
if (!this.SetValue(sensor, str2, ValueDateString))
{
e.StatusCode = 404;
break;
}
str1 = "ok";
break;
}
}
e.Result = str1;
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, ex.Message, (object)ex);
}
finally
{
Manager.semaphore.Release();
}
}
}
}

View File

@ -0,0 +1,153 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.ParseExtensions
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using MySqlConnector;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
#nullable disable
namespace Sensormat
{
public static class ParseExtensions
{
public static string XMLSerializeData<T>(this T data)
{
StringBuilder stringBuilder = new StringBuilder();
new XmlSerializer(typeof(T)).Serialize((TextWriter)new StringWriter(stringBuilder), (object)data);
return stringBuilder.ToString();
}
public static T XMLDeserializeData<T>(this string dataXML)
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(dataXML);
return (T)new XmlSerializer(typeof(T)).Deserialize((XmlReader)new XmlNodeReader((XmlNode)xmlDocument.DocumentElement));
}
public static T ParseObject<T>(this MySqlDataReader rd) where T : class, new()
{
var type = typeof(T);
var instance = new T();
// Properties vorbereiten (Case-insensitive, nur schreibbare)
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanWrite)
.ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
for (int ordinal = 0; ordinal < rd.FieldCount; ordinal++)
{
if (rd.IsDBNull(ordinal)) continue;
string fieldName = rd.GetName(ordinal);
if (!props.TryGetValue(fieldName, out var propertyInfo)) continue; // Spalte ohne passende Property
object value = rd.GetValue(ordinal);
Type targetType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
try
{
object? converted = ConvertTo(value, targetType);
propertyInfo.SetValue(instance, converted);
}
catch
{
// Optional: Logging einbauen, wenn eine Spalte mal nicht passt.
// throw; // oder bewusst schlucken
}
}
return instance;
}
public static object ParseObject(this MySqlDataReader rd, Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
var instance = Activator.CreateInstance(type)
?? throw new InvalidOperationException($"Kann Instanz von {type.FullName} nicht erzeugen.");
// Schreibbare Properties case-insensitiv mappen
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanWrite)
.ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
for (int ordinal = 0; ordinal < rd.FieldCount; ordinal++)
{
if (rd.IsDBNull(ordinal)) continue;
string fieldName = rd.GetName(ordinal);
if (!props.TryGetValue(fieldName, out var propertyInfo)) continue;
object value = rd.GetValue(ordinal);
Type targetType = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
try
{
object? converted = ConvertTo(value, targetType);
propertyInfo.SetValue(instance, converted);
}
catch
{
// Optional: Logging/Tracing hier einbauen
// Wenn du strikt sein willst: throw;
}
}
return instance;
}
private static object? ConvertTo(object value, Type targetType)
{
if (value == null) return null;
// Schon richtig typisiert?
if (targetType.IsInstanceOfType(value)) return value;
// Enums (Zahl oder Name)
if (targetType.IsEnum)
{
if (value is string s) return Enum.Parse(targetType, s, ignoreCase: true);
var underlying = Enum.GetUnderlyingType(targetType);
var num = Convert.ChangeType(value, underlying, CultureInfo.InvariantCulture);
return Enum.ToObject(targetType, num!);
}
// Guid
if (targetType == typeof(Guid))
return value is Guid g ? g : Guid.Parse(value.ToString()!);
// DateTimeOffset
if (targetType == typeof(DateTimeOffset))
{
if (value is DateTimeOffset dto) return dto;
if (value is DateTime dt) return new DateTimeOffset(dt);
return DateTimeOffset.Parse(value.ToString()!, CultureInfo.InvariantCulture);
}
// DateTime: ChangeType kann das meist, sonst Parse
if (targetType == typeof(DateTime) && value is string sdt)
return DateTime.Parse(sdt, CultureInfo.InvariantCulture);
// Bool aus 0/1 oder "0"/"1"
if (targetType == typeof(bool) && value is IConvertible)
{
var s = value.ToString();
if (s == "0") return false;
if (s == "1") return true;
}
// Fallback: Convert.ChangeType
return Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture);
}
}
}

View File

@ -0,0 +1,29 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.Program
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using System;
using System.Reflection;
#nullable disable
namespace Sensormat
{
internal class Program
{
private static void Main(string[] args)
{
try
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, "START");
new Manager().Run();
}
catch (Exception ex)
{
EventLog.Write(((MemberInfo)MethodBase.GetCurrentMethod()).Name, ex.Message, (object)ex);
Console.WriteLine((object)ex);
}
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,56 @@
// Decompiled with JetBrains decompiler
// Type: Sensormat.SQLExtensions
// Assembly: Sensormat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 49795081-3467-4846-904D-9A360FB2FA3C
// Assembly location: \\192.168.178.26\Freigabe\Sensormat.dll
using MySqlConnector;
using Sensormat.Entities;
using System.Collections.Generic;
#nullable disable
namespace Sensormat
{
public static class SQLExtensions
{
public static IEnumerable<Sensoren> GetSensoren(this MySqlConnection connection)
{
using (MySqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "SELECT * FROM tblSensoren WHERE Aktiv <> 0";
MySqlDataReader reader = cmd.ExecuteReader();
try
{
while (true)
{
if (reader.HasRows)
{
if (reader.Read())
yield return reader.ParseObject<Sensoren>();
else
break;
}
else
goto label_5;
}
}
finally
{
reader?.Dispose();
}
yield break;
label_5:
reader = (MySqlDataReader)null;
}
}
public static void CallCalculate(this MySqlConnection connection)
{
using (MySqlCommand command = connection.CreateCommand())
{
command.CommandText = "CALL spSensorCalculate; ";
command.ExecuteNonQuery();
}
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Reference Include="MySqlConnector">
<HintPath>References\MySqlConnector.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>References\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,8 @@
using System;
namespace Shelly
{
public class Class1
{
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Sensormat\Sensormat.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\Sensormat\References\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,20 @@
// Decompiled with JetBrains decompiler
// Type: Shelly.Shelly1PM.ResultMeters
// Assembly: Shelly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 2DDB6D74-8C37-490A-B928-07FB0E37240C
// Assembly location: \\192.168.178.26\Freigabe\Shelly.dll
using System;
#nullable disable
namespace Shelly.Shelly1PM
{
public class ResultMeters
{
public Decimal power { get; set; }
public Decimal overload { get; set; }
public Decimal total { get; set; }
}
}

View File

@ -0,0 +1,14 @@
// Decompiled with JetBrains decompiler
// Type: Shelly.Shelly1PM.ResultSet
// Assembly: Shelly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 2DDB6D74-8C37-490A-B928-07FB0E37240C
// Assembly location: \\192.168.178.26\Freigabe\Shelly.dll
#nullable disable
namespace Shelly.Shelly1PM
{
public class ResultSet
{
public ResultMeters[] meters { get; set; }
}
}

View File

@ -0,0 +1,39 @@
// Decompiled with JetBrains decompiler
// Type: Shelly.Shelly1PM.SensorEntity
// Assembly: Shelly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 2DDB6D74-8C37-490A-B928-07FB0E37240C
// Assembly location: \\192.168.178.26\Freigabe\Shelly.dll
using Newtonsoft.Json;
using Sensormat;
using Sensormat.Entities;
using System;
#nullable disable
namespace Shelly.Shelly1PM
{
public class SensorEntity : ISensor
{
public override bool Execute()
{
try
{
int id = this.Sensor.ID;
new ResultSet().XMLSerializeData<ResultSet>();
string str = this.HttpRequest(this.Sensor.URL);
if (str != null)
{
this.LastValue = JsonConvert.DeserializeObject<ResultSet>(str).meters?[0]?.total.ToString();
this.LastValueDate = new DateTime?(DateTime.Now);
return true;
}
}
catch (Exception ex)
{
Console.WriteLine((object)ex);
this.ErrorMsg = ex.Message;
}
return false;
}
}
}

View File

@ -0,0 +1,16 @@
// Decompiled with JetBrains decompiler
// Type: Shelly.Shelly3PM.Config
// Assembly: Shelly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 2DDB6D74-8C37-490A-B928-07FB0E37240C
// Assembly location: \\192.168.178.26\Freigabe\Shelly.dll
#nullable disable
namespace Shelly.Shelly3PM
{
public class Config
{
public bool Sum { get; set; }
public int index { get; set; }
}
}

View File

@ -0,0 +1,24 @@
// Decompiled with JetBrains decompiler
// Type: Shelly.Shelly3PM.ResultMeters
// Assembly: Shelly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 2DDB6D74-8C37-490A-B928-07FB0E37240C
// Assembly location: \\192.168.178.26\Freigabe\Shelly.dll
using System;
#nullable disable
namespace Shelly.Shelly3PM
{
public class ResultMeters
{
public Decimal current { get; set; }
public Decimal power { get; set; }
public Decimal voltage { get; set; }
public Decimal total { get; set; }
public Decimal total_returned { get; set; }
}
}

View File

@ -0,0 +1,14 @@
// Decompiled with JetBrains decompiler
// Type: Shelly.Shelly3PM.ResultSet
// Assembly: Shelly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 2DDB6D74-8C37-490A-B928-07FB0E37240C
// Assembly location: \\192.168.178.26\Freigabe\Shelly.dll
#nullable disable
namespace Shelly.Shelly3PM
{
public class ResultSet
{
public ResultMeters[] emeters { get; set; }
}
}

View File

@ -0,0 +1,47 @@
// Decompiled with JetBrains decompiler
// Type: Shelly.Shelly3PM.SensorEntity
// Assembly: Shelly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 2DDB6D74-8C37-490A-B928-07FB0E37240C
// Assembly location: \\192.168.178.26\Freigabe\Shelly.dll
using Newtonsoft.Json;
using Sensormat;
using Sensormat.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
#nullable disable
namespace Shelly.Shelly3PM
{
public class SensorEntity : ISensor
{
private Config cfg;
public override bool Execute()
{
try
{
this.cfg = this.getConfiguration<Config>();
new ResultSet().XMLSerializeData<ResultSet>();
string str = this.HttpRequest(this.Sensor.URL);
if (str != null)
{
ResultSet resultSet = JsonConvert.DeserializeObject<ResultSet>(str);
if (this.cfg.Sum)
this.LastValue = ((IEnumerable<ResultMeters>)resultSet.emeters).Sum<ResultMeters>((Func<ResultMeters, Decimal>)(f => f.total)).ToString();
else
this.LastValue = resultSet.emeters?[this.cfg.index]?.total.ToString();
this.LastValueDate = new DateTime?(DateTime.Now);
return true;
}
}
catch (Exception ex)
{
Console.WriteLine((object)ex);
this.ErrorMsg = ex.Message;
}
return false;
}
}
}