399 lines
17 KiB
C#
399 lines
17 KiB
C#
using System.Globalization;
|
|
using System.Net.NetworkInformation;
|
|
using System.Text;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
|
|
namespace ShellyExporter
|
|
{
|
|
public class Metrics
|
|
{
|
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
|
|
public enum Type
|
|
{
|
|
PlugS = 1,
|
|
Em3 = 2,
|
|
TemperatureAddon = 3,
|
|
Pm1 = 4
|
|
}
|
|
|
|
public enum Version
|
|
{
|
|
Gen1 = 1,
|
|
Gen2 = 2,
|
|
Gen3 = 3
|
|
}
|
|
|
|
public class Data
|
|
{
|
|
public string? Power { get; set; }
|
|
public string? Overpower { get; set; }
|
|
public bool? IsValid { get; set; }
|
|
public string? Timestamp { get; set; }
|
|
public string? Total { get; set; }
|
|
public string? Temperature { get; set; }
|
|
public string? Voltage { get; set; }
|
|
public string? Current { get; set; }
|
|
|
|
public string? Emeters1Power { get; set; }
|
|
public string? Emeters1Pf { get; set; }
|
|
public string? Emeters1Current { get; set; }
|
|
public string? Emeters1Voltage { get; set; }
|
|
public bool? Emeters1IsValid { get; set; }
|
|
public string? Emeters1Total { get; set; }
|
|
public string? Emeters1TotalReturned { get; set; }
|
|
|
|
public string? Emeters2Power { get; set; }
|
|
public string? Emeters2Pf { get; set; }
|
|
public string? Emeters2Current { get; set; }
|
|
public string? Emeters2Voltage { get; set; }
|
|
public bool? Emeters2IsValid { get; set; }
|
|
public string? Emeters2Total { get; set; }
|
|
public string? Emeters2TotalReturned { get; set; }
|
|
|
|
public string? Emeters3Power { get; set; }
|
|
public string? Emeters3Pf { get; set; }
|
|
public string? Emeters3Current { get; set; }
|
|
public string? Emeters3Voltage { get; set; }
|
|
public bool? Emeters3IsValid { get; set; }
|
|
public string? Emeters3Total { get; set; }
|
|
public string? Emeters3TotalReturned { get; set; }
|
|
|
|
}
|
|
|
|
public static async Task<StringBuilder> Get(string ip, string name, Version shellyVersion, Type type, string id)
|
|
{
|
|
var sb = new StringBuilder();
|
|
var online = true;
|
|
var error = false;
|
|
try
|
|
{
|
|
using var pinger = new Ping();
|
|
var reply = pinger.Send(ip, TimeSpan.FromSeconds(2), null, null);
|
|
if (reply.Status != IPStatus.Success)
|
|
{
|
|
Logger.Error($"PingDevice:Status {reply.Status}");
|
|
online = false;
|
|
}
|
|
}
|
|
catch (PingException e)
|
|
{
|
|
Logger.Error(e, "PingDevice");
|
|
online = false;
|
|
error = true;
|
|
}
|
|
|
|
var path = $"http://{ip}";
|
|
|
|
Data data = null;
|
|
if (online)
|
|
{
|
|
try
|
|
{
|
|
switch (type)
|
|
{
|
|
case Type.PlugS:
|
|
switch (shellyVersion)
|
|
{
|
|
case Version.Gen1:
|
|
data = await GetPlugSGen1(path);
|
|
break;
|
|
case Version.Gen2:
|
|
data = await GetPlugSGen2(path);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(shellyVersion), shellyVersion, null);
|
|
}
|
|
break;
|
|
case Type.Em3:
|
|
switch (shellyVersion)
|
|
{
|
|
case Version.Gen1:
|
|
data = await Get3EmGen1(path);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
break;
|
|
case Type.TemperatureAddon:
|
|
switch (shellyVersion)
|
|
{
|
|
case Version.Gen2:
|
|
data = await GetTemperatureAddonGen2(path, id);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
break;
|
|
case Type.Pm1:
|
|
switch (shellyVersion)
|
|
{
|
|
case Version.Gen3:
|
|
data = await GetPm1Gen3(path);
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Error(e, "GetDataFromDevice");
|
|
error = true;
|
|
}
|
|
}
|
|
|
|
sb.AppendLine($"device_online{{item=\"{name}\"}} {(online ? 1 : 0)}");
|
|
sb.AppendLine($"device_error_retrieving_data{{item=\"{name}\"}} {(error ? 1 : 0)}");
|
|
if (!online || error)
|
|
return sb;
|
|
|
|
//Prestavljeno na sestevek vseh faz
|
|
if (data.Power != null)
|
|
sb.AppendLine($"meters_power_wats{{item=\"{name}\"}} {data.Power}");
|
|
if (data.Overpower != null)
|
|
sb.AppendLine($"meters_overpower_wats{{item=\"{name}\"}} " + data.Overpower);
|
|
if (data.IsValid != null)
|
|
sb.AppendLine($"meters_is_valid{{item=\"{name}\"}} " + ((bool)data.IsValid ? 1 : 0));
|
|
if (data.Timestamp != null)
|
|
sb.AppendLine($"meters_timestamp{{item=\"{name}\"}} " + data.Timestamp);
|
|
if (data.Total != null)
|
|
sb.AppendLine($"meters_power_total{{item=\"{name}\"}} " + data.Total);
|
|
if (data.Voltage != null)
|
|
sb.AppendLine($"meters_voltage_V{{item=\"{name}\"}} " + data.Voltage);
|
|
if (data.Current != null)
|
|
sb.AppendLine($"meters_current_A{{item=\"{name}\"}} " + data.Current);
|
|
if (data.Temperature != null)
|
|
sb.AppendLine($"temperature{{item=\"{name}\"}} " + data.Temperature);
|
|
|
|
if (data.Emeters1Power != null)
|
|
sb.AppendLine($"emeters_1_power{{item=\"{name}\"}} " + data.Emeters1Power);
|
|
if (data.Emeters1Pf != null)
|
|
sb.AppendLine($"emeters_1_pf{{item=\"{name}\"}} " + data.Emeters1Pf);
|
|
if (data.Emeters1Current != null)
|
|
sb.AppendLine($"emeters_1_current{{item=\"{name}\"}} " + data.Emeters1Current);
|
|
if (data.Emeters1Voltage != null)
|
|
sb.AppendLine($"emeters_1_voltage{{item=\"{name}\"}} " + data.Emeters1Voltage);
|
|
if (data.Emeters1IsValid != null)
|
|
sb.AppendLine($"emeters_1_is_valid{{item=\"{name}\"}} " + ((bool)data.Emeters1IsValid ? 1 : 0));
|
|
if (data.Emeters1Total != null)
|
|
sb.AppendLine($"emeters_1_total{{item=\"{name}\"}} " + data.Emeters1Total);
|
|
if (data.Emeters1TotalReturned != null)
|
|
sb.AppendLine($"emeters_1_total_returned{{item=\"{name}\"}} " + data.Emeters1TotalReturned);
|
|
|
|
if (data.Emeters2Power != null)
|
|
sb.AppendLine($"emeters_2_power{{item=\"{name}\"}} " + data.Emeters2Power);
|
|
if (data.Emeters2Pf != null)
|
|
sb.AppendLine($"emeters_2_pf{{item=\"{name}\"}} " + data.Emeters2Pf);
|
|
if (data.Emeters2Current != null)
|
|
sb.AppendLine($"emeters_2_current{{item=\"{name}\"}} " + data.Emeters2Current);
|
|
if (data.Emeters2Voltage != null)
|
|
sb.AppendLine($"emeters_2_voltage{{item=\"{name}\"}} " + data.Emeters2Voltage);
|
|
if (data.Emeters2IsValid != null)
|
|
sb.AppendLine($"emeters_2_is_valid{{item=\"{name}\"}} " + ((bool)data.Emeters2IsValid ? 1 : 0));
|
|
if (data.Emeters2Total != null)
|
|
sb.AppendLine($"emeters_2_total{{item=\"{name}\"}} " + data.Emeters2Total);
|
|
if (data.Emeters2TotalReturned != null)
|
|
sb.AppendLine($"emeters_2_total_returned{{item=\"{name}\"}} " + data.Emeters2TotalReturned);
|
|
|
|
if (data.Emeters3Power != null)
|
|
sb.AppendLine($"emeters_3_power{{item=\"{name}\"}} " + data.Emeters3Power);
|
|
if (data.Emeters3Pf != null)
|
|
sb.AppendLine($"emeters_3_pf{{item=\"{name}\"}} " + data.Emeters3Pf);
|
|
if (data.Emeters3Current != null)
|
|
sb.AppendLine($"emeters_3_current{{item=\"{name}\"}} " + data.Emeters3Current);
|
|
if (data.Emeters3Voltage != null)
|
|
sb.AppendLine($"emeters_3_voltage{{item=\"{name}\"}} " + data.Emeters3Voltage);
|
|
if (data.Emeters3IsValid != null)
|
|
sb.AppendLine($"emeters_3_is_valid{{item=\"{name}\"}} " + ((bool)data.Emeters3IsValid ? 1 : 0));
|
|
if (data.Emeters3Total != null)
|
|
sb.AppendLine($"emeters_3_total{{item=\"{name}\"}} " + data.Emeters3Total);
|
|
if (data.Emeters3TotalReturned != null)
|
|
sb.AppendLine($"emeters_3_total_returned{{item=\"{name}\"}} " + data.Emeters3TotalReturned);
|
|
|
|
//Ce gre za 3PM
|
|
if (data.Power != null
|
|
&& data is { Emeters1Power: not null, Emeters2Power: not null, Emeters3Power: not null })
|
|
{
|
|
var emetersPowerTotal = 0d;
|
|
double.TryParse(data.Emeters1Power, CultureInfo.InvariantCulture, out var emeters1Power);
|
|
double.TryParse(data.Emeters2Power, CultureInfo.InvariantCulture, out var emeters2Power);
|
|
double.TryParse(data.Emeters3Power, CultureInfo.InvariantCulture, out var emeters3Power);
|
|
|
|
sb.AppendLine($"meters_power_wats{{item=\"{name}\"}} {(emeters1Power + emeters2Power + emeters3Power)}");
|
|
}
|
|
|
|
return sb;
|
|
}
|
|
|
|
private static async Task<Data> GetPlugSGen1(string path)
|
|
{
|
|
var data = new Data();
|
|
var client = new HttpClient();
|
|
var response = await client.GetStringAsync(path + "/status");
|
|
|
|
dynamic responseObject = JsonConvert.DeserializeObject(response);
|
|
|
|
if (responseObject == null)
|
|
return data;
|
|
|
|
if (responseObject.meters != null)
|
|
{
|
|
data.Power = responseObject.meters[0].power;
|
|
data.Overpower = responseObject.meters[0].overpower;
|
|
data.IsValid = responseObject.meters[0].is_valid;
|
|
data.Timestamp = responseObject.meters[0].timestamp;
|
|
data.Total = responseObject.meters[0].total;
|
|
}
|
|
|
|
if (responseObject.tmp.tC != null)
|
|
{
|
|
data.Temperature = responseObject.tmp.tC;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
private static async Task<Data> Get3EmGen1(string path)
|
|
{
|
|
var data = new Data();
|
|
var client = new HttpClient();
|
|
var response = await client.GetStringAsync(path + "/status");
|
|
|
|
dynamic responseObject = JsonConvert.DeserializeObject<dynamic>(response);
|
|
|
|
if (responseObject == null)
|
|
return data;
|
|
|
|
if (responseObject.total_power != null)
|
|
{
|
|
data.Total = responseObject.total_power;
|
|
}
|
|
|
|
if (responseObject.emeters != null)
|
|
{
|
|
data.Emeters1Power = responseObject.emeters[0].power;
|
|
data.Emeters1Pf = responseObject.emeters[0].pf;
|
|
data.Emeters1Current = responseObject.emeters[0].current;
|
|
data.Emeters1Voltage = responseObject.emeters[0].voltage;
|
|
data.Emeters1IsValid = responseObject.emeters[0].is_valid;
|
|
data.Emeters1Total = responseObject.emeters[0].total;
|
|
data.Emeters1TotalReturned = responseObject.emeters[0].total_returned;
|
|
}
|
|
|
|
if (responseObject.emeters != null)
|
|
{
|
|
data.Emeters2Power = responseObject.emeters[1].power;
|
|
data.Emeters2Pf = responseObject.emeters[1].pf;
|
|
data.Emeters2Current = responseObject.emeters[1].current;
|
|
data.Emeters2Voltage = responseObject.emeters[1].voltage;
|
|
data.Emeters2IsValid = responseObject.emeters[1].is_valid;
|
|
data.Emeters2Total = responseObject.emeters[1].total;
|
|
data.Emeters2TotalReturned = responseObject.emeters[1].total_returned;
|
|
}
|
|
|
|
if (responseObject.emeters != null)
|
|
{
|
|
data.Emeters3Power = responseObject.emeters[2].power;
|
|
data.Emeters3Pf = responseObject.emeters[2].pf;
|
|
data.Emeters3Current = responseObject.emeters[2].current;
|
|
data.Emeters3Voltage = responseObject.emeters[2].voltage;
|
|
data.Emeters3IsValid = responseObject.emeters[2].is_valid;
|
|
data.Emeters3Total = responseObject.emeters[2].total;
|
|
data.Emeters3TotalReturned = responseObject.emeters[2].total_returned;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
private static async Task<Data> GetPlugSGen2(string path)
|
|
{
|
|
var data = new Data();
|
|
var client = new HttpClient();
|
|
var response = await client.GetStringAsync(path + "/rpc/Switch.GetStatus?id=0");
|
|
|
|
dynamic responseObject = JsonConvert.DeserializeObject(response);
|
|
|
|
if (responseObject == null)
|
|
return data;
|
|
|
|
if (responseObject.apower != null)
|
|
data.Power = responseObject.apower;
|
|
|
|
if (responseObject.current != null)
|
|
data.Current = responseObject.current;
|
|
|
|
if (responseObject.voltage != null)
|
|
data.Voltage = responseObject.voltage;
|
|
|
|
if (responseObject.aenergy != null)
|
|
{
|
|
if (responseObject.aenergy.total != null)
|
|
data.Total = (Convert.ToDecimal(responseObject.aenergy.total) * (decimal)60).ToString(CultureInfo.InvariantCulture);
|
|
|
|
if (responseObject.aenergy.minute_ts != null)
|
|
data.Timestamp = responseObject.aenergy.minute_ts;
|
|
}
|
|
|
|
if (responseObject.temperature != null
|
|
&& responseObject.temperature.tC != null)
|
|
data.Temperature = responseObject.temperature.tC;
|
|
|
|
return data;
|
|
}
|
|
|
|
private static async Task<Data> GetTemperatureAddonGen2(string path, string id)
|
|
{
|
|
var data = new Data();
|
|
var client = new HttpClient();
|
|
var response = await client.GetStringAsync(path + $"/rpc/Temperature.GetStatus?id={id}");
|
|
|
|
var responseObject = JsonConvert.DeserializeObject<Classes.TemperatureGetStatusResponse>(response);
|
|
|
|
if (responseObject == null)
|
|
return data;
|
|
|
|
if (responseObject.TemperatureC != null)
|
|
data.Temperature = responseObject.TemperatureC;
|
|
|
|
return data;
|
|
}
|
|
|
|
private static async Task<Data> GetPm1Gen3(string path)
|
|
{
|
|
var data = new Data();
|
|
var client = new HttpClient();
|
|
var response = await client.GetStringAsync(path + "/rpc/PM1.GetStatus?id=0");
|
|
|
|
var responseObject = JsonConvert.DeserializeObject<Classes.Pm1GetStatusResponse>(response);
|
|
|
|
if (responseObject == null)
|
|
return data;
|
|
|
|
if (responseObject.Apower != null)
|
|
data.Power = responseObject.Apower;
|
|
|
|
if (responseObject.Current != null)
|
|
data.Current = responseObject.Current;
|
|
|
|
if (responseObject.Voltage != null)
|
|
data.Voltage = responseObject.Voltage;
|
|
|
|
if (responseObject.Aenergy != null)
|
|
{
|
|
if (responseObject.Aenergy.Total != null)
|
|
data.Total = (Convert.ToDecimal(responseObject.Aenergy.Total) * (decimal)60).ToString(CultureInfo.InvariantCulture);
|
|
|
|
if (responseObject.Aenergy.MinuteTimeStamp!= null)
|
|
data.Timestamp = responseObject.Aenergy.MinuteTimeStamp;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
}
|
|
}
|