Skip to content

Commit

Permalink
v1.4.0-beta.27
Browse files Browse the repository at this point in the history
- added digital signal processing library (NWAves)
- new program: time series filters example API
- added selectable data filter in statistics view
  • Loading branch information
genemars committed Mar 11, 2023
1 parent 8a97e8d commit ea00abc
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 77 deletions.
2 changes: 2 additions & 0 deletions assets/build/all/app/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
"combine": "Combine",
"compare": "Compare",
"graph_mode": "Graph Mode",
"data_filter": "Data filter",
"data_filter_none": "(none)",
"show_fields": "Fields",
"compare_modules": "Compare with",
"not_set": "Not set",
Expand Down
2 changes: 2 additions & 0 deletions assets/build/all/app/assets/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
"combine": "Combina",
"compare": "Confronta",
"graph_mode": "Tipo Grafico",
"data_filter": "Filtro dati",
"data_filter_none": "(nessuno)",
"show_fields": "Campi",
"compare_modules": "Confronta con",
"not_set": "Non impostato",
Expand Down
40 changes: 24 additions & 16 deletions assets/build/all/app/assets/i18n/module/en.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
{
"stats.time_range":
"Time range",
"stats.last_minute":
"Last minute",
"stats.last_ten_minutes":
"Last 10 minutes",
"stats.last_half_hour":
"Last 30 minutes",
"stats.last_hour":
"Last hour",
"stats.last_three_hours":
"Last 3 hours",
"stats.last_six_hours":
"Last 6 hours",
"stats.last_twelve_hours":
"Last 12 hours",
"stats.last_twentyfour_hours":
"Last 24 hours"
"stats.one_second":
"One second",
"stats.five_seconds":
"5 seconds",
"stats.ten_seconds":
"10 seconds",
"stats.half_minute":
"30 seconds",
"stats.one_minute":
"One minute",
"stats.ten_minutes":
"10 minutes",
"stats.half_hour":
"30 minutes",
"stats.one_hour":
"One hour",
"stats.three_hours":
"3 hours",
"stats.six_hours":
"6 hours",
"stats.twelve_hours":
"12 hours",
"stats.twentyfour_hours":
"24 hours"
}
40 changes: 24 additions & 16 deletions assets/build/all/app/assets/i18n/module/it.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
{
"stats.time_range":
"Intervallo",
"stats.last_minute":
"Ultimo minuto",
"stats.last_ten_minutes":
"Ultimi 10 minuti",
"stats.last_half_hour":
"Ultima mezz'ora",
"stats.last_hour":
"Ultima ora",
"stats.last_three_hours":
"Ultime 3 ore",
"stats.last_six_hours":
"Ultime 6 ore",
"stats.last_twelve_hours":
"Ultime 12 ore",
"stats.last_twentyfour_hours":
"Ultime 24 ore"
"stats.one_second":
"Un secondo",
"stats.five_seconds":
"5 secondi",
"stats.ten_seconds":
"10 secondi",
"stats.half_minute":
"30 secondi",
"stats.one_minute":
"Un minuto",
"stats.ten_minutes":
"10 minuti",
"stats.half_hour":
"30 minuti",
"stats.one_hour":
"Un'ora",
"stats.three_hours":
"3 ore",
"stats.six_hours":
"6 ore",
"stats.twelve_hours":
"12 ore",
"stats.twentyfour_hours":
"24 ore"
}
2 changes: 1 addition & 1 deletion assets/build/all/app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@

</div>

<script src="runtime.b92e2ca178ebbf4a.js" type="module"></script><script src="polyfills.710b144f4805f4b0.js" type="module"></script><script src="main.6e0cec9b0905a17b.js" type="module"></script>
<script src="runtime.b92e2ca178ebbf4a.js" type="module"></script><script src="polyfills.710b144f4805f4b0.js" type="module"></script><script src="main.4de4b0ec78f21ce3.js" type="module"></script>

</body></html>

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions assets/build/all/app/ngsw.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"configVersion": 1,
"timestamp": 1678284933122,
"timestamp": 1678551458013,
"index": "/app/index.html",
"assetGroups": [
{
Expand All @@ -15,7 +15,7 @@
"/app/613.16b9c52c0ae74833.js",
"/app/859.0f150be9c99a6b5a.js",
"/app/index.html",
"/app/main.6e0cec9b0905a17b.js",
"/app/main.4de4b0ec78f21ce3.js",
"/app/manifest.webmanifest",
"/app/polyfills.710b144f4805f4b0.js",
"/app/runtime.b92e2ca178ebbf4a.js",
Expand Down Expand Up @@ -410,12 +410,12 @@
"/app/assets/fonts/Roboto-Latin-300.woff": "fec6225507c70951797db15985fe0bf87195d6ee",
"/app/assets/fonts/Roboto-Latin-400.woff": "fec6225507c70951797db15985fe0bf87195d6ee",
"/app/assets/fonts/Roboto-Latin-500.woff": "7416b5d46c615d2786a604d71d334b605d41cc73",
"/app/assets/i18n/en.json": "40b5c6cdf7748ff7d9307e70e12db9004efe13fc",
"/app/assets/i18n/en.json": "8ce7cbf7fe68f3961e589ab1616a9d06ce3ca7d6",
"/app/assets/i18n/homegenie/en.json": "d8ea4950b51f0db6dc54e1c7247e06dd9d1502be",
"/app/assets/i18n/homegenie/it.json": "45981bcdbaa0e57ce93621cd82d5329ad8fa834c",
"/app/assets/i18n/it.json": "e44474e1205c51ba28a139a0c61595b7401e1a66",
"/app/assets/i18n/module/en.json": "78357e1e0adcee2b80c71e596cc1f9581a22d8e9",
"/app/assets/i18n/module/it.json": "cc900e710937c4f3d003f85e6943409bbdc4d2b3",
"/app/assets/i18n/it.json": "cb63d28177c4e0f3d23fa1cbc03f528d408ad20e",
"/app/assets/i18n/module/en.json": "b91f73dda960b9c0cb26aeee6820019fc893b833",
"/app/assets/i18n/module/it.json": "02c2a0c1deab911e7e527548003afa717bd8d03e",
"/app/assets/i18n/widgets/en.json": "81775f6536411948d4d4c6e054a768a21793ab24",
"/app/assets/i18n/widgets/it.json": "6435f9a7978c18e24fc8d79db404ac4d190fb50a",
"/app/assets/i18n/zigbee/en.json": "3353db6fb123f979e1811a724026886a9993fe14",
Expand Down Expand Up @@ -724,8 +724,8 @@
"/app/assets/widgets/weather/images_alt/weather.svg": "c719c09048977fd40688272316b35ddf1bdf89e8",
"/app/assets/widgets/weather/style.css": "1b70730e73885cc0ee83566eaf584008d34e2255",
"/app/assets/workers/typings-worker.js": "8df10d867c12d36cdebfb7e16caacd0020db301f",
"/app/index.html": "12279b6f7ed37e147591c867e01990e599a54c55",
"/app/main.6e0cec9b0905a17b.js": "de4175fd3b0f16ba00f7bc3fc0d1e766e0667ec6",
"/app/index.html": "9006de6c51a40aea0ba127285addbad1a359f35c",
"/app/main.4de4b0ec78f21ce3.js": "11913520717e6765c0ed4de7f0872f39f6ae71dc",
"/app/manifest.webmanifest": "d47bb07a495e27ddf072f8702df373f79b4eb183",
"/app/polyfills.710b144f4805f4b0.js": "594a5ea1b9d3f9cbc4f363eca84eda2c8bb8a901",
"/app/runtime.b92e2ca178ebbf4a.js": "b50d841a4c50d466c34aab3267d3fb4afe87dede",
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"repository":"homegenie","id":"homegenie-base","version":"1.0.0","description":"HomeGenie base package. This should always be installed.","programs":[{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"111","id":"client-configs","required":true,"version":"1.0.1","checksum":"AC96494FCA5A5E953B728A669BAF7CA3","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"142","id":"e-mail-account","required":true,"version":"1.0.0","checksum":"8A42A1D70C35CF3C855AF8761795F5B7","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"95","id":"events-logging","required":true,"version":"1.0.0","checksum":"25467F93E2AA07645AE54E5D5BB9587E","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"77","id":"mqtt-network","required":true,"version":"1.0.1","checksum":"60A252D5988007FD051C58E78ACDDA5D","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"34","id":"openweathermap","required":true,"version":"1.0.0","checksum":"F22CC262E2D8B59CF3C97348D552398E","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"505","id":"remote-control","required":true,"version":"1.0.0","checksum":"3CCE84C3D6FAFC582974FA8A189B3665","installed":false}],"modules":null,"groups":[{"repository":null,"packageId":null,"packageVersion":null,"hid":"Dashboard","id":"0","required":false,"version":"0","checksum":null,"installed":false}],"schedules":[{"repository":null,"packageId":null,"packageVersion":null,"hid":"System.UpdateCheck","id":"0","required":false,"version":"0","checksum":null,"installed":false}]}
{"repository":"homegenie","id":"homegenie-base","version":"1.0.0","description":"HomeGenie base package. This should always be installed.","programs":[{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"111","id":"client-configs","required":true,"version":"1.0.1","checksum":"AC96494FCA5A5E953B728A669BAF7CA3","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"142","id":"e-mail-account","required":true,"version":"1.0.0","checksum":"8A42A1D70C35CF3C855AF8761795F5B7","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"95","id":"events-logging","required":true,"version":"1.0.0","checksum":"25467F93E2AA07645AE54E5D5BB9587E","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"77","id":"mqtt-network","required":true,"version":"1.0.1","checksum":"60A252D5988007FD051C58E78ACDDA5D","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"34","id":"openweathermap","required":true,"version":"1.0.0","checksum":"F22CC262E2D8B59CF3C97348D552398E","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"505","id":"remote-control","required":true,"version":"1.0.0","checksum":"3CCE84C3D6FAFC582974FA8A189B3665","installed":false},{"repository":"homegenie","packageId":"homegenie-base","packageVersion":"1.0.0","hid":"570","id":"time-series-filters","required":true,"version":"1.0.0","checksum":"749ED822713EF777CDDAE4E60D2F22E2","installed":false}],"modules":null,"groups":[{"repository":null,"packageId":null,"packageVersion":null,"hid":"Dashboard","id":"0","required":false,"version":"0","checksum":null,"installed":false}],"schedules":[{"repository":null,"packageId":null,"packageVersion":null,"hid":"System.UpdateCheck","id":"0","required":false,"version":"0","checksum":null,"installed":false}]}
172 changes: 172 additions & 0 deletions assets/build/all/data/packages/homegenie/homegenie-base/programs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -791,4 +791,176 @@ Program.GoBackground();
<Type>CSharp</Type>
<IsEnabled>true</IsEnabled>
</ProgramBlock>
<ProgramBlock>
<ScriptSetup>#region program-context

#using NWaves.Filters
#using NWaves.Operations

const int windowSize = 9;

ValueStatistics ApplySimpleAverageFilter(ModuleParameter parameter, double startTime, double endTime, double chartWidth) {
startTime = (long)startTime;
endTime = (long)endTime;
var timeSpan = (endTime - startTime);
var timeSpanMin = (timeSpan / 2);

// Copy parameter values history to a new object
var stats = new ValueStatistics() {
History = new TsList&lt;ValueStatistics.StatValue&gt;(
parameter.Statistics.History
.Where(sv =&gt; sv.UnixTimestamp &gt;= startTime - timeSpanMin &amp;&amp; sv.UnixTimestamp &lt;= endTime)
.ToList()
)
};
stats.History.Reverse();

// Process time series
if (startTime &gt; 0 &amp;&amp; stats.History.Count &gt; 0)
{
var stepMs = (timeSpan / chartWidth);
if (stepMs &lt; 1000) stepMs = 1000;
var resampledList = new List&lt;ValueStatistics.StatValue&gt;();
var cts = stats.History.First().UnixTimestamp;
cts -= (cts % stepMs);
cts -= stepMs;
var sum = 0D;
var count = 0;
int i = 0;
var itemTimestamp = DateTime.UtcNow;
while (i &lt; stats.History.Count)
{
var item = stats.History[i];
if (item.UnixTimestamp &gt;= cts)
{
var resampled = new ValueStatistics.StatValue(
sum / count,
itemTimestamp
);
resampledList.Add(resampled);
sum =0; count = 0;
cts += stepMs;
}
sum += item.Value;
itemTimestamp = item.Timestamp;
count++;
i++;
}
stats.History = new TsList&lt;ValueStatistics.StatValue&gt;(resampledList);
}
return stats;
}

ValueStatistics ApplyFilter(NWaves.Filters.Base.IFilter filter, ModuleParameter parameter, double startTime, double endTime, double chartWidth) {
var stats = ApplySimpleAverageFilter(parameter, startTime, endTime, chartWidth);

// Process time series
var samples = stats.History
.Select(sv =&gt; (float)sv.Value)
.ToArray();
var signal = new DiscreteSignal(50/*Hz sampling rate*/, samples);
var smoothedSignal = filter.ApplyTo(signal);
var lst = new List&lt;ValueStatistics.StatValue&gt;();
int boundsGap = (windowSize - 1) / 2;
for (int c = 0; c &lt; stats.History.Count - boundsGap; c++)
{
var sv = stats.History[c];
lst.Add(new ValueStatistics.StatValue(smoothedSignal[c + boundsGap], sv.Timestamp));
}

stats.History = new TsList&lt;ValueStatistics.StatValue&gt;(lst);
return stats;
}

#endregion

Program.Run();</ScriptSetup>
<ScriptSource>When.WebServiceCallReceived("DataProcessing.Filters/List/Series", (args) =&gt; {
return new string[]{
"SimpleAverage",
"MovingAverage",
"SavitzkyGolay"
};
});

When.WebServiceCallReceived("DataProcessing.Filters/Series/SimpleAverage", (args) =&gt; {
var request = Program.ParseApiCall(args);
var module = Modules.InDomain(request.Domain)
.WithAddress(request.Address)
.Get();
if (module.Exists) {
var parameter = module.Parameter(request.Command);
var startTime = double.Parse(request.GetOption(0));
var endTime = double.Parse(request.GetOption(1));
var chartWidth = double.Parse(request.GetOption(2));

var stats = ApplySimpleAverageFilter(parameter, startTime, endTime, chartWidth);
stats.History.Reverse();
return stats;
}
return new ResponseStatus(Status.Error, $"Unknown module '{request.Domain}:{request.Address}'");
});

When.WebServiceCallReceived("DataProcessing.Filters/Series/MovingAverage", (args) =&gt; {
var request = Program.ParseApiCall(args);
var module = Modules.InDomain(request.Domain)
.WithAddress(request.Address)
.Get();
if (module.Exists) {
var parameter = module.Parameter(request.Command);
var startTime = double.Parse(request.GetOption(0));
var endTime = double.Parse(request.GetOption(1));
var chartWidth = double.Parse(request.GetOption(2));

var filter = new MovingAverageFilter(windowSize);
var stats = ApplyFilter(filter, parameter, startTime, endTime, chartWidth);
stats.History.Reverse();
return stats;
}
return new ResponseStatus(Status.Error, $"Unknown module '{request.Domain}:{request.Address}'");
});

When.WebServiceCallReceived("DataProcessing.Filters/Series/SavitzkyGolay", (args) =&gt; {
var request = Program.ParseApiCall(args);
var module = Modules.InDomain(request.Domain)
.WithAddress(request.Address)
.Get();
if (module.Exists) {
var parameter = module.Parameter(request.Command);
var startTime = double.Parse(request.GetOption(0));
var endTime = double.Parse(request.GetOption(1));
var chartWidth = double.Parse(request.GetOption(2));

var filter = new SavitzkyGolayFilter(windowSize);
var stats = ApplyFilter(filter, parameter, startTime, endTime, chartWidth);
stats.History.Reverse();
return stats;
}
return new ResponseStatus(Status.Error, $"Unknown module '{request.Domain}:{request.Address}'");
});

Program.GoBackground();
</ScriptSource>
<ScriptErrors />
<PackageInfo>
<Repository>homegenie</Repository>
<PackageId>homegenie-base</PackageId>
<PackageVersion>1.0.0</PackageVersion>
<Id>time-series-filters</Id>
<Version>1.0.0</Version>
<Required>true</Required>
<Checksum>749ED822713EF777CDDAE4E60D2F22E2</Checksum>
</PackageInfo>
<Domain>HomeAutomation.HomeGenie.Automation</Domain>
<Address>570</Address>
<Name>Time Series Filters</Name>
<Description>Example filters for time series that can be used in the statistics view.
</Description>
<Group>Data Processing</Group>
<Features />
<AutoRestartEnabled>false</AutoRestartEnabled>
<Cloneable>false</Cloneable>
<Type>csharp</Type>
<IsEnabled>true</IsEnabled>
</ProgramBlock>
</ArrayOfProgramBlock>
10 changes: 10 additions & 0 deletions src/HomeGenie/Automation/Engines/CSharpAppFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ public static class CSharpAppFactory
"Innovative.SolarCalculator",
"LiteDB",
"OpenSource.UPnP",
"NWaves.Signals",
"NWaves.Filters",
"NWaves.Filters.Base",
"NWaves.Operations",
"NWaves.Utils",
#if !NETCOREAPP
"Raspberry",
"Raspberry.Timers",
Expand Down Expand Up @@ -226,6 +231,9 @@ private HomeGenie.Automation.MethodRunResult Setup()
MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "Iot.Device.Bindings.dll")),
MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "UnitsNet.dll")),

// Data / Signal processing
MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "NWaves.dll")),

MetadataReference.CreateFromFile(Path.Combine(homeGenieDir, "HomeGenie.dll")),

MetadataReference.CreateFromFile(Path.Combine(dotNetCoreDir, "System.dll")),
Expand Down Expand Up @@ -353,6 +361,8 @@ private HomeGenie.Automation.MethodRunResult Setup()
compilerParams.ReferencedAssemblies.Add("UPnP.dll");

compilerParams.ReferencedAssemblies.Add("MQTTnet.dll");

compilerParams.ReferencedAssemblies.Add("NWaves.dll");

compilerParams.ReferencedAssemblies.Add("Raspberry.IO.dll");
compilerParams.ReferencedAssemblies.Add("Raspberry.IO.Components.dll");
Expand Down
2 changes: 1 addition & 1 deletion src/HomeGenie/Automation/Scripting/EventsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public EventsHelper ProgramStopping(Func<bool> handler)
/// <example>
/// Example:
/// <code>
/// When.ModuleParameterChange( (module, parameter) =>
/// When.ModuleParameterChanged( (module, parameter) =>
/// {
/// if (module.Is("Kitchen Motion Sensor") && parameter.Is("Status.Level"))
/// {
Expand Down
Loading

0 comments on commit ea00abc

Please sign in to comment.