2023-02-16 12:57:06 +00:00
|
|
|
using System.Diagnostics;
|
|
|
|
using System.Text.Json;
|
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
using Flurl.Http;
|
2023-02-25 14:53:58 +00:00
|
|
|
using InnovEnergy.App.SaliMax.Controller;
|
|
|
|
using InnovEnergy.App.SaliMax.SaliMaxRelays;
|
|
|
|
using InnovEnergy.App.SaliMax.SystemConfig;
|
|
|
|
using InnovEnergy.Lib.Devices.AMPT;
|
|
|
|
using InnovEnergy.Lib.Devices.Battery48TL;
|
2023-02-16 12:57:06 +00:00
|
|
|
using InnovEnergy.Lib.Devices.EmuMeter;
|
|
|
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc;
|
|
|
|
using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc;
|
2023-02-25 14:53:58 +00:00
|
|
|
using InnovEnergy.Lib.Time.Unix;
|
2023-04-04 14:37:37 +00:00
|
|
|
using InnovEnergy.Lib.Utils;
|
2023-02-23 12:45:09 +00:00
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
#pragma warning disable IL2026
|
|
|
|
|
2023-02-23 12:45:09 +00:00
|
|
|
|
2023-02-25 14:53:58 +00:00
|
|
|
namespace InnovEnergy.App.SaliMax;
|
2023-02-16 12:57:06 +00:00
|
|
|
|
|
|
|
internal static class Program
|
|
|
|
{
|
|
|
|
private const UInt32 UpdateIntervalSeconds = 2;
|
2023-02-23 12:45:09 +00:00
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
public static async Task Main(String[] args)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
await Run();
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
2023-02-23 12:45:09 +00:00
|
|
|
await File.AppendAllTextAsync(Config.LogSalimaxLog,
|
|
|
|
String.Join(Environment.NewLine, UnixTime.Now + " \n" + e));
|
2023-02-16 12:57:06 +00:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static async Task Run()
|
|
|
|
{
|
|
|
|
Console.WriteLine("Starting SaliMax");
|
|
|
|
|
2023-04-04 14:37:37 +00:00
|
|
|
var batteryNodes = new Byte[] { 2, 3 };
|
|
|
|
|
|
|
|
var batteryTty = "/dev/ttyUSB0";
|
|
|
|
|
|
|
|
var relaysIp = "10.0.1.1";
|
|
|
|
var truConvertAcIp = "10.0.2.1";
|
|
|
|
var truConvertDcIp = "10.0.3.1";
|
|
|
|
var gridMeterIp = "10.0.4.1";
|
|
|
|
var internalMeter = "10.0.4.2";
|
|
|
|
var amptIp = "10.0.5.1";
|
|
|
|
|
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
var s3Config = new S3Config
|
|
|
|
{
|
2023-04-04 14:37:37 +00:00
|
|
|
Bucket = "saliomameiringen",
|
|
|
|
Region = "sos-ch-dk-2",
|
|
|
|
Provider = "exo.io",
|
2023-02-16 12:57:06 +00:00
|
|
|
ContentType = "text/plain; charset=utf-8",
|
2023-04-04 14:37:37 +00:00
|
|
|
Key = "EXO2bf0cbd97fbfa75aa36ed46f",
|
|
|
|
Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs"
|
2023-02-16 12:57:06 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#if DEBUG
|
2023-02-23 12:45:09 +00:00
|
|
|
var inverterDevice = new TruConvertAcDevice("127.0.0.1", 5001);
|
|
|
|
var dcDcDevice = new TruConvertDcDevice("127.0.0.1", 5002);
|
|
|
|
var gridMeterDevice = new EmuMeterDevice("127.0.0.1", 5003);
|
|
|
|
var saliMaxRelaysDevice = new SaliMaxRelaysDevice("127.0.0.1", 5004);
|
|
|
|
var amptDevice = new AmptCommunicationUnit("127.0.0.1", 5005);
|
2023-02-16 12:57:06 +00:00
|
|
|
var acInToAcOutMeterDevice = new EmuMeterDevice("127.0.0.1", 5003); // TODO: use real device
|
2023-02-23 12:45:09 +00:00
|
|
|
var secondBattery48TlDevice = Battery48TlDevice.Fake();
|
|
|
|
var firstBattery48TlDevice =Battery48TlDevice.Fake();;
|
2023-02-16 12:57:06 +00:00
|
|
|
var salimaxConfig = new SalimaxConfig();
|
2023-02-23 12:45:09 +00:00
|
|
|
#else
|
2023-04-04 14:37:37 +00:00
|
|
|
|
|
|
|
var batteries = batteryNodes.Select(n => new Battery48TlDevice(batteryTty, n)).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
var inverterDevice = new TruConvertAcDevice(truConvertAcIp);
|
|
|
|
var dcDcDevice = new TruConvertDcDevice(truConvertDcIp);
|
|
|
|
|
|
|
|
var gridMeterDevice = new EmuMeterDevice(gridMeterIp);
|
|
|
|
var acInToAcOutMeterDevice = new EmuMeterDevice(internalMeter); // TODO: use real device
|
|
|
|
|
|
|
|
var amptDevice = new AmptCommunicationUnit(amptIp);
|
|
|
|
|
|
|
|
var saliMaxRelaysDevice = new SaliMaxRelaysDevice(relaysIp);
|
2023-02-23 12:45:09 +00:00
|
|
|
var salimaxConfig = new SalimaxConfig();
|
2023-02-16 12:57:06 +00:00
|
|
|
#endif
|
2023-02-23 12:45:09 +00:00
|
|
|
// This is will be always add manually ? or do we need to read devices automatically in a range of IP @
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-04-04 14:37:37 +00:00
|
|
|
|
2023-02-23 12:45:09 +00:00
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
StatusRecord ReadStatus()
|
|
|
|
{
|
2023-04-04 14:37:37 +00:00
|
|
|
var combinedBatteryStatus = batteries
|
|
|
|
.Select(b => b.ReadStatus())
|
|
|
|
.NotNull()
|
|
|
|
.ToList()
|
|
|
|
.Combine();
|
|
|
|
|
|
|
|
// var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray();
|
2023-02-23 12:45:09 +00:00
|
|
|
// var inverterStatusArray = inverterDevices.Select(b => b.ReadStatus()).NotNull().ToArray();
|
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
return new StatusRecord
|
|
|
|
{
|
|
|
|
InverterStatus = inverterDevice.ReadStatus(),
|
|
|
|
DcDcStatus = dcDcDevice.ReadStatus(),
|
2023-04-04 14:37:37 +00:00
|
|
|
BatteriesStatus = combinedBatteryStatus,
|
2023-02-16 12:57:06 +00:00
|
|
|
AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(),
|
|
|
|
GridMeterStatus = gridMeterDevice.ReadStatus(),
|
|
|
|
SaliMaxRelayStatus = saliMaxRelaysDevice.ReadStatus(),
|
|
|
|
AmptStatus = amptDevice.ReadStatus(),
|
|
|
|
SalimaxConfig = salimaxConfig.Load().Result,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-23 12:45:09 +00:00
|
|
|
|
|
|
|
var startTime = UnixTime.Now;
|
2023-02-16 12:57:06 +00:00
|
|
|
const Int32 delayTime = 10;
|
2023-02-23 12:45:09 +00:00
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
Console.WriteLine("press ctrl-C to stop");
|
|
|
|
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
var t = UnixTime.Now;
|
|
|
|
while (t.Ticks % UpdateIntervalSeconds != 0)
|
|
|
|
{
|
|
|
|
await Task.Delay(delayTime);
|
|
|
|
t = UnixTime.Now;
|
|
|
|
}
|
2023-02-23 12:45:09 +00:00
|
|
|
|
2023-02-16 12:57:06 +00:00
|
|
|
var status = ReadStatus();
|
2023-02-23 12:45:09 +00:00
|
|
|
#if BatteriesAllowed
|
2023-02-16 12:57:06 +00:00
|
|
|
|
2023-02-23 12:45:09 +00:00
|
|
|
var jsonLog = status.ToLog(t);
|
|
|
|
await UploadTimeSeries(s3Config, jsonLog, t);
|
2023-02-16 12:57:06 +00:00
|
|
|
var controlRecord = Controller.Controller.SaliMaxControl(status);
|
|
|
|
Controller.Controller.WriteControlRecord(controlRecord, inverterDevice, dcDcDevice, saliMaxRelaysDevice);
|
|
|
|
|
2023-02-23 12:45:09 +00:00
|
|
|
//JsonSerializer.Serialize(jsonLog, JsonOptions).WriteLine(ConsoleColor.DarkBlue);
|
|
|
|
#endif
|
2023-02-23 16:58:33 +00:00
|
|
|
Topology.Print(status);
|
2023-02-23 12:45:09 +00:00
|
|
|
|
|
|
|
while (UnixTime.Now == t)
|
2023-02-16 12:57:06 +00:00
|
|
|
await Task.Delay(delayTime);
|
|
|
|
}
|
|
|
|
// ReSharper disable once FunctionNeverReturns
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-02-23 12:45:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
// to delete not used anymore
|
2023-02-16 12:57:06 +00:00
|
|
|
[Conditional("RELEASE")]
|
|
|
|
private static void ReleaseWriteLog(JsonObject jsonLog, UnixTime timestamp)
|
|
|
|
{
|
2023-02-23 12:45:09 +00:00
|
|
|
// WriteToFile(jsonLog, "/home/debian/DataSaliMax/" + timestamp); // this is was for beaglebone TODO
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[Conditional("DEBUG")]
|
|
|
|
private static void DebugWriteLog(JsonObject jsonLog, UnixTime timestamp)
|
|
|
|
{
|
|
|
|
WriteToFile(jsonLog, "/home/atef/JsonData/" + timestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void WriteToFile(Object obj, String fileName)
|
|
|
|
{
|
|
|
|
var jsonString = JsonSerializer.Serialize(obj, JsonOptions);
|
|
|
|
File.WriteAllText(fileName, jsonString);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
|
|
{
|
|
|
|
WriteIndented = true,
|
|
|
|
IgnoreReadOnlyProperties = false,
|
|
|
|
Converters = { new JsonStringEnumConverter() },
|
|
|
|
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals,
|
|
|
|
//TODO
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private static async Task UploadTimeSeries(S3Config config, JsonObject json, UnixTime unixTime)
|
|
|
|
{
|
|
|
|
var payload = JsonSerializer.Serialize(json, JsonOptions);
|
|
|
|
var s3Path = unixTime.Ticks + ".json";
|
|
|
|
var request = config.CreatePutRequest(s3Path);
|
|
|
|
var response = await request.PutAsync(new StringContent(payload));
|
|
|
|
|
|
|
|
if (response.StatusCode != 200)
|
|
|
|
{
|
|
|
|
Console.WriteLine("ERROR: PUT");
|
|
|
|
var error = response.GetStringAsync();
|
|
|
|
Console.WriteLine(error);
|
|
|
|
}
|
|
|
|
}
|
2023-02-23 12:45:09 +00:00
|
|
|
|
|
|
|
private static async Task UploadTopology(S3Config config, JsonObject json, UnixTime unixTime)
|
|
|
|
{
|
|
|
|
var payload = JsonSerializer.Serialize(json, JsonOptions);
|
|
|
|
var s3Path = "topology" + unixTime.Ticks + ".json";
|
|
|
|
var request = config.CreatePutRequest(s3Path);
|
|
|
|
var response = await request.PutAsync(new StringContent(payload));
|
|
|
|
|
|
|
|
if (response.StatusCode != 200)
|
|
|
|
{
|
|
|
|
Console.WriteLine("ERROR: PUT");
|
|
|
|
var error = response.GetStringAsync();
|
|
|
|
Console.WriteLine(error);
|
|
|
|
}
|
|
|
|
}
|
2023-02-16 12:57:06 +00:00
|
|
|
}
|