diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 9326b35..eab337c 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -4,8 +4,6 @@ on:
push:
branches:
- release
- tags:
- - v[0-9]+\.[0-9]+\.[0-9]+
jobs:
build:
@@ -17,6 +15,8 @@ jobs:
- arch: "amd64"
rid: "linux-musl-x64"
runs-on: ubuntu-latest
+ permissions:
+ packages: write
steps:
- name: checkout
uses: actions/checkout@v3
@@ -26,7 +26,7 @@ jobs:
dotnet-version: 7.0.x
- name: build_release
run: |
- cd TestAddon/App
+ cd FiatChampAddon/FiatClient
dotnet publish -r ${{ matrix.rid }} --configuration Release --self-contained -o build/
- name: docker_login
uses: docker/login-action@v2.0.0
@@ -38,6 +38,5 @@ jobs:
uses: home-assistant/builder@2022.09.0
with:
args: |
- --test
--${{ matrix.arch }} \
- --target TestAddon
+ --target FiatChampAddon
diff --git a/FiatChampAddon/CHANGELOG.md b/FiatChampAddon/CHANGELOG.md
index b563517..e24c136 100644
--- a/FiatChampAddon/CHANGELOG.md
+++ b/FiatChampAddon/CHANGELOG.md
@@ -1,5 +1,16 @@
# CHANGELOG
+## 2.0.13 - 2022-10-16
+- km to miles conversion
+- distance sensors export unit of measurement to home assistant (km or mi)
+- more fitting icons for some sensors
+- obfuscate mail account in log
+- fix debug logging
+
+## 2.0.7 - 2022-10-10
+- supports remote door locking and unlocking. dangerous command... disabled by default.
+- more logging
+
## 2.0.6 - 2022-10-06
- fixed high memory usage with prebuilt image. as a bonus installation an upgrades should be a lot faster now.
diff --git a/FiatChampAddon/Dockerfile b/FiatChampAddon/Dockerfile
index 542372e..ea8a58f 100644
--- a/FiatChampAddon/Dockerfile
+++ b/FiatChampAddon/Dockerfile
@@ -2,15 +2,13 @@
ARG BUILD_FROM
FROM $BUILD_FROM
-ARG BUILD_ARCH
-
RUN apk add icu-libs
RUN apk add icu
COPY run.sh /run.sh
RUN chmod a+x /run.sh
-COPY FiatClient/build/$BUILD_ARCH/ /build/.
+COPY FiatClient/build/ /build/.
LABEL org.opencontainers.image.source https://github.com/wubbl0rz/FiatChamp
diff --git a/FiatChampAddon/FiatClient/AppConfig.cs b/FiatChampAddon/FiatClient/AppConfig.cs
index ba9885b..f7ab25e 100644
--- a/FiatChampAddon/FiatClient/AppConfig.cs
+++ b/FiatChampAddon/FiatClient/AppConfig.cs
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Text;
+using System.Text.RegularExpressions;
using Newtonsoft.Json;
namespace FiatChamp;
@@ -17,12 +18,18 @@ public record AppConfig
public bool AutoRefreshLocation { get; set; } = false;
public bool AutoRefreshBattery { get; set; } = false;
public bool EnableDangerousCommands { get; set; } = false;
+ public bool ConvertKmToMiles { get; set; } = false;
public bool DevMode { get; set; } = false;
+ public bool UseFakeApi { get; set; } = false;
+ public bool Debug { get; set; } = false;
- public override string ToString()
+ public string ToStringWithoutSecrets()
{
+ var user = this.FiatUser[0..2] + new string('*', this.FiatUser[2..].Length);
+
var tmp = this with
{
+ FiatUser = user,
FiatPw = new string('*', this.FiatPw.Length),
MqttPw = new string('*', this.MqttPw.Length),
FiatPin = new string('*', this.FiatPin?.Length ?? 0)
@@ -30,7 +37,7 @@ public override string ToString()
return JsonConvert.SerializeObject(tmp, Formatting.Indented);
}
-
+
public bool IsPinSet()
{
return !string.IsNullOrWhiteSpace(this.FiatPin);
diff --git a/FiatChampAddon/FiatClient/FiatChamp.csproj b/FiatChampAddon/FiatClient/FiatChamp.csproj
index 2b2a789..38e303d 100644
--- a/FiatChampAddon/FiatClient/FiatChamp.csproj
+++ b/FiatChampAddon/FiatClient/FiatChamp.csproj
@@ -16,6 +16,8 @@
+
+
diff --git a/FiatChampAddon/FiatClient/FiatClient.cs b/FiatChampAddon/FiatClient/FiatClient.cs
index 227d89e..e29c835 100644
--- a/FiatChampAddon/FiatClient/FiatClient.cs
+++ b/FiatChampAddon/FiatClient/FiatClient.cs
@@ -2,12 +2,286 @@
using Amazon;
using Amazon.CognitoIdentity;
using Amazon.Runtime;
-using FiatChamp;
using Flurl;
using Flurl.Http;
+using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using Serilog;
-public class FiatClient
+namespace FiatChamp;
+
+public interface IFiatClient
+{
+ Task LoginAndKeepSessionAlive();
+ Task SendCommand(string vin, string command, string pin, string action);
+ Task Fetch();
+}
+
+public class FiatClientFake : IFiatClient
+{
+ public Task LoginAndKeepSessionAlive()
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task SendCommand(string vin, string command, string pin, string action)
+ {
+ return Task.CompletedTask;
+ }
+
+ public Task Fetch()
+ {
+ var vehicle = JsonConvert.DeserializeObject("""
+ {
+ "RegStatus": "COMPLETED_STAGE_3",
+ "Color": "BLUE",
+ "Year": 2022,
+ "TsoBodyCode": "",
+ "NavEnabledHu": false,
+ "Language": "",
+ "CustomerRegStatus": "Y",
+ "Radio": "",
+ "ActivationSource": "DEALER",
+ "Nickname": "KEKW",
+ "Vin": "LDM1SN7DHD7DHSHJ6753D",
+ "Company": "FCA",
+ "Model": 332,
+ "ModelDescription": "Neuer 500 3+1",
+ "TcuType": 2,
+ "Make": "FIAT",
+ "BrandCode": "12",
+ "SoldRegion": "EMEA"
+ }
+ """);
+
+ vehicle.Details = JObject.Parse("""
+ {
+ "vehicleInfo": {
+ "totalRangeADA": null,
+ "odometer": {
+ "odometer": {
+ "value": "1234",
+ "unit": "km"
+ }
+ },
+ "daysToService": "null",
+ "fuel": {
+ "fuelAmountLevel": null,
+ "isFuelLevelLow": false,
+ "distanceToEmpty": {
+ "value": "150",
+ "unit": "km"
+ },
+ "fuelAmount": {
+ "value": "null",
+ "unit": "null"
+ }
+ },
+ "oilLevel": {
+ "oilLevel": null
+ },
+ "tyrePressure": [
+ {
+ "warning": false,
+ "pressure": {
+ "value": "null",
+ "unit": "kPa"
+ },
+ "type": "FL",
+ "status": "NORMAL"
+ },
+ {
+ "warning": false,
+ "pressure": {
+ "value": "null",
+ "unit": "kPa"
+ },
+ "type": "FR",
+ "status": "NORMAL"
+ },
+ {
+ "warning": false,
+ "pressure": {
+ "value": "null",
+ "unit": "kPa"
+ },
+ "type": "RL",
+ "status": "NORMAL"
+ },
+ {
+ "warning": false,
+ "pressure": {
+ "value": "null",
+ "unit": "kPa"
+ },
+ "type": "RR",
+ "status": "NORMAL"
+ }
+ ],
+ "batteryInfo": {
+ "batteryStatus": "0",
+ "batteryVoltage": {
+ "value": "14.55",
+ "unit": "volts"
+ }
+ },
+ "tripsInfo": {
+ "trips": [
+ {
+ "totalElectricDistance": {
+ "value": "null",
+ "unit": "km"
+ },
+ "name": "TripA",
+ "totalDistance": {
+ "value": "1013",
+ "unit": "km"
+ },
+ "energyUsed": {
+ "value": "null",
+ "unit": "kmpl"
+ },
+ "averageEnergyUsed": {
+ "value": "null",
+ "unit": "kmpl"
+ },
+ "totalHybridDistance": {
+ "value": "null",
+ "unit": "km"
+ }
+ },
+ {
+ "totalElectricDistance": {
+ "value": "null",
+ "unit": "km"
+ },
+ "name": "TripB",
+ "totalDistance": {
+ "value": "14",
+ "unit": "km"
+ },
+ "energyUsed": {
+ "value": "null",
+ "unit": "kmpl"
+ },
+ "averageEnergyUsed": {
+ "value": "null",
+ "unit": "kmpl"
+ },
+ "totalHybridDistance": {
+ "value": "null",
+ "unit": "km"
+ }
+ }
+ ]
+ },
+ "batPwrUsageDisp": null,
+ "distanceToService": {
+ "distanceToService": {
+ "value": "5127.0",
+ "unit": "km"
+ }
+ },
+ "wheelCount": 4,
+ "hvacPwrUsageDisp": null,
+ "mtrPwrUsageDisp": null,
+ "tpmsvehicle": false,
+ "hVBatSOH": null,
+ "isTPMSVehicle": false,
+ "timestamp": 1665779022952
+ },
+ "evInfo": {
+ "chargeSchedules": [],
+ "battery": {
+ "stateOfCharge": 72,
+ "chargingLevel": "LEVEL_2",
+ "plugInStatus": true,
+ "timeToFullyChargeL2": 205,
+ "chargingStatus": "CHARGING",
+ "totalRange": 172,
+ "distanceToEmpty": {
+ "value": 172,
+ "unit": "km"
+ }
+ },
+ "timestamp": 1665822611085,
+ "schedules": [
+ {
+ "chargeToFull": false,
+ "scheduleType": "NONE",
+ "enableScheduleType": false,
+ "scheduledDays": {
+ "sunday": false,
+ "saturday": false,
+ "tuesday": false,
+ "wednesday": false,
+ "thursday": false,
+ "friday": false,
+ "monday": false
+ },
+ "startTime": "00:00",
+ "endTime": "00:00",
+ "cabinPriority": false,
+ "repeatSchedule": true
+ },
+ {
+ "chargeToFull": false,
+ "scheduleType": "NONE",
+ "enableScheduleType": false,
+ "scheduledDays": {
+ "sunday": false,
+ "saturday": false,
+ "tuesday": false,
+ "wednesday": false,
+ "thursday": false,
+ "friday": false,
+ "monday": false
+ },
+ "startTime": "00:00",
+ "endTime": "00:00",
+ "cabinPriority": false,
+ "repeatSchedule": true
+ },
+ {
+ "chargeToFull": false,
+ "scheduleType": "NONE",
+ "enableScheduleType": false,
+ "scheduledDays": {
+ "sunday": false,
+ "saturday": false,
+ "tuesday": false,
+ "wednesday": false,
+ "thursday": false,
+ "friday": false,
+ "monday": false
+ },
+ "startTime": "00:00",
+ "endTime": "00:00",
+ "cabinPriority": false,
+ "repeatSchedule": true
+ }
+ ]
+ },
+ "timestamp": 1665822611085
+ }
+ """);
+
+ vehicle.Location = JsonConvert.DeserializeObject("""
+ {
+ "TimeStamp": 1665779022952,
+ "Longitude": 4.1234365,
+ "Latitude": 69.4765989,
+ "Altitude": 40.346462111,
+ "Bearing": 0,
+ "IsLocationApprox": true
+ }
+ """);
+
+ return Task.FromResult(new[] { vehicle });
+ }
+}
+
+public class FiatClient : IFiatClient
{
private readonly string _loginApiKey = "3_mOx_J2dRgjXYCdyhchv3b5lhi54eBcdCTX4BI8MORqmZCoQWhA0mV2PTlptLGUQI";
private readonly string _apiKey = "2wGyL6PHec9o1UeLPYpoYa1SkEWqeBur9bLsi24i";
@@ -51,13 +325,14 @@ public async Task LoginAndKeepSessionAlive()
{
try
{
- Console.WriteLine("REFRESH SESSION");
+ Log.Information("REFRESH SESSION");
await this.Login();
}
catch (Exception e)
{
- Console.WriteLine("ERROR WHILE REFRESH SESSION");
- e.Message.Dump();
+
+ Log.Error("ERROR WHILE REFRESH SESSION");
+ Log.Debug("{0}", e);
}
}
});
@@ -72,7 +347,7 @@ private async Task Login()
.WithCookies(_cookieJar)
.GetJsonAsync();
- loginResponse.Dump();
+ Log.Debug("{0}", loginResponse.Dump());
loginResponse.ThrowOnError("Login failed.");
@@ -90,7 +365,7 @@ private async Task Login()
}))
.ReceiveJson();
- authResponse.Dump();
+ Log.Debug("{0}", authResponse.Dump());
authResponse.ThrowOnError("Authentication failed.");
@@ -106,7 +381,7 @@ private async Task Login()
.WithCookies(_cookieJar)
.GetJsonAsync();
- jwtResponse.Dump();
+ Log.Debug("{0}", jwtResponse.Dump());
jwtResponse.ThrowOnError("Authentication failed.");
@@ -120,10 +395,10 @@ private async Task Login()
})
.ReceiveJson();
+ Log.Debug("{0}", identityResponse.Dump());
+
identityResponse.ThrowOnError("Identity failed.");
- identityResponse.Dump();
-
var client = new AmazonCognitoIdentityClient(new AnonymousAWSCredentials(), RegionEndpoint.EUWest1);
var res = await client.GetCredentialsForIdentityAsync(identityResponse.IdentityId,
@@ -172,9 +447,8 @@ private Dictionary WithFiatDefaultParameter(Dictionary();
- pinAuthResponse.Dump();
+ Log.Debug("{0}", pinAuthResponse.Dump());
var json = new
{
@@ -207,7 +481,7 @@ public async Task SendCommand(string vin, string command, string pin, string act
.PostJsonAsync(json)
.ReceiveJson();
- commandResponse.Dump();
+ Log.Debug("{0}", commandResponse.Dump());
}
public async Task Fetch()
@@ -223,8 +497,8 @@ public async Task Fetch()
.WithHeaders(WithAwsDefaultParameter(_apiKey))
.AwsSign(awsCredentials)
.GetJsonAsync();
-
- vehicleResponse.Dump();
+
+ Log.Debug("{0}", vehicleResponse.Dump());
foreach (var vehicle in vehicleResponse.Vehicles)
{
@@ -234,8 +508,8 @@ public async Task Fetch()
.WithHeaders(WithAwsDefaultParameter(_apiKey))
.AwsSign(awsCredentials)
.GetJsonAsync();
-
- vehicleDetails.Dump();
+
+ Log.Debug("{0}", vehicleDetails.Dump());
vehicle.Details = vehicleDetails;
@@ -248,9 +522,10 @@ public async Task Fetch()
vehicle.Location = vehicleLocation;
- vehicleLocation.Dump();
+ Log.Debug("{0}", vehicleLocation.Dump());
}
return vehicleResponse.Vehicles;
}
-}
\ No newline at end of file
+}
+
diff --git a/FiatChampAddon/FiatClient/FiatCommand.cs b/FiatChampAddon/FiatClient/FiatCommand.cs
index 2f98cdb..a8a5cbe 100644
--- a/FiatChampAddon/FiatClient/FiatCommand.cs
+++ b/FiatChampAddon/FiatClient/FiatCommand.cs
@@ -8,6 +8,8 @@ public class FiatCommand
public static readonly FiatCommand ROPRECOND_OFF = new() { Message = "ROPRECOND", IsDangerous = true };
public static readonly FiatCommand ROTRUNKUNLOCK = new() { Message = "ROTRUNKUNLOCK" };
public static readonly FiatCommand ROTRUNKLOCK = new() { Message = "ROTRUNKLOCK" };
+ public static readonly FiatCommand RDU = new() { Message = "RDU", IsDangerous = true };
+ public static readonly FiatCommand RDL = new() { Message = "RDL", IsDangerous = true };
public bool IsDangerous { get; set; }
public required string Message { get; init; }
diff --git a/FiatChampAddon/FiatClient/Helper.cs b/FiatChampAddon/FiatClient/Helper.cs
index f776f3e..5e48ff1 100644
--- a/FiatChampAddon/FiatClient/Helper.cs
+++ b/FiatChampAddon/FiatClient/Helper.cs
@@ -55,9 +55,8 @@ public static IFlurlRequest AwsSign(this IFlurlRequest request, ImmutableCredent
return request;
}
-
- [Conditional("DEBUG")]
- public static void Dump(this object o)
+
+ public static string Dump(this object o)
{
try
{
@@ -73,22 +72,20 @@ public static void Dump(this object o)
try
{
var json = JObject.Parse(str);
- Console.WriteLine(json);
+ return json.ToString(Formatting.Indented);
}
catch (Exception e)
{
- // ignored
+ return str;
}
-
- return;
}
- Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
-
+ return JsonConvert.SerializeObject(result, Formatting.Indented);
+
}
catch (Exception)
{
- // ignored
+ return o.GetType().ToString();
}
}
}
\ No newline at end of file
diff --git a/FiatChampAddon/FiatClient/HomeAssistant.cs b/FiatChampAddon/FiatClient/HomeAssistant.cs
index 683b82d..4f57745 100644
--- a/FiatChampAddon/FiatClient/HomeAssistant.cs
+++ b/FiatChampAddon/FiatClient/HomeAssistant.cs
@@ -6,8 +6,10 @@ public abstract class HaEntity
protected readonly string _name;
protected readonly HaDevice _haDevice;
protected readonly string _id;
+
+ public string Name => _name;
- public HaEntity(SimpleMqttClient mqttClient, string name, HaDevice haDevice)
+ protected HaEntity(SimpleMqttClient mqttClient, string name, HaDevice haDevice)
{
_mqttClient = mqttClient;
_name = name;
@@ -74,9 +76,12 @@ await _mqttClient.Pub(_configTopic, $$"""
public class HaSensor : HaEntity
{
public string Value { get; set; } = "";
+ public string Icon { get; set; } = "mdi:eye";
+ public string Unit { get; set; } = "";
+
private readonly string _stateTopic;
private readonly string _configTopic;
-
+
public HaSensor(SimpleMqttClient mqttClient, string name, HaDevice haDevice) : base(mqttClient, name, haDevice)
{
_stateTopic = $"homeassistant/sensor/{_id}/state";
@@ -99,6 +104,8 @@ await _mqttClient.Pub(_configTopic, $$"""
"name":"{{ _haDevice.Name }}",
"sw_version":"{{ _haDevice.Version }}"},
"name":"{{ _name }}",
+ "unit_of_measurement":"{{ this.Unit }}",
+ "icon":"{{ this.Icon }}",
"state_topic":"{{ _stateTopic }}",
"unique_id":"{{ _id }}",
"platform":"mqtt"
diff --git a/FiatChampAddon/FiatClient/PollyHttpClientFactory.cs b/FiatChampAddon/FiatClient/PollyHttpClientFactory.cs
index bfff0ef..baab963 100644
--- a/FiatChampAddon/FiatClient/PollyHttpClientFactory.cs
+++ b/FiatChampAddon/FiatClient/PollyHttpClientFactory.cs
@@ -1,6 +1,7 @@
using AwsSignatureVersion4;
using Flurl.Http.Configuration;
using Polly;
+using Serilog;
namespace FiatChamp;
@@ -19,8 +20,9 @@ protected override Task SendAsync(HttpRequestMessage reques
{
var ex = delegateResult.Exception as HttpRequestException;
var result = delegateResult.Result?.StatusCode.ToString() ?? ex?.StatusCode.ToString() ?? ex?.Message;
-
- Console.WriteLine($"Error connecting to {request.RequestUri}. Result: {result}. Retrying in {time}");
+
+ Log.Warning("Error connecting to {0}. Result: {1}. Retrying in {2}",
+ request.RequestUri, result, time);
});
return retryPolicy.ExecuteAsync(ct => { return base.SendAsync(request, ct); }, cancellationToken);
diff --git a/FiatChampAddon/FiatClient/Program.cs b/FiatChampAddon/FiatClient/Program.cs
index a7d2c7e..b2c645e 100644
--- a/FiatChampAddon/FiatClient/Program.cs
+++ b/FiatChampAddon/FiatClient/Program.cs
@@ -1,15 +1,21 @@
using System.Collections.Concurrent;
+using System.Globalization;
using Cocona;
using FiatChamp;
using FiatChamp.HA;
using Flurl.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+using Newtonsoft.Json.Linq;
+using Serilog;
+using Serilog.Events;
var builder = CoconaApp.CreateBuilder();
builder.Configuration.AddEnvironmentVariables("FiatChamp_");
+//todo: integrate reports and events
+
builder.Services.AddOptions()
.Bind(builder.Configuration)
.ValidateDataAnnotations()
@@ -21,11 +27,18 @@
var appConfig = builder.Configuration.Get();
var forceLoopResetEvent = new AutoResetEvent(false);
+Log.Logger = new LoggerConfiguration()
+ .MinimumLevel.Is(appConfig.Debug ? LogEventLevel.Debug : LogEventLevel.Information)
+ .WriteTo.Console()
+ .CreateLogger();
+
await app.RunAsync(async (CoconaAppContext ctx) =>
{
- Console.WriteLine("===== CONFIG ===== \n\n{0}\n", appConfig);
-
- var fiatClient = new FiatClient(appConfig.FiatUser, appConfig.FiatPw);
+ Log.Information("{0}", appConfig.ToStringWithoutSecrets());
+ Log.Debug("{0}", appConfig.Dump());
+
+ IFiatClient fiatClient =
+ appConfig.UseFakeApi ? new FiatClientFake() : new FiatClient(appConfig.FiatUser, appConfig.FiatPw);
var mqttClient = new SimpleMqttClient(appConfig.MqttServer,
appConfig.MqttPort,
@@ -37,10 +50,10 @@ await app.RunAsync(async (CoconaAppContext ctx) =>
while (!ctx.CancellationToken.IsCancellationRequested)
{
- Console.WriteLine($"FETCH DATA... {DateTime.Now}");
-
+ Log.Information("Now fetching new data...");
+
GC.Collect();
-
+
try
{
await fiatClient.LoginAndKeepSessionAlive();
@@ -51,14 +64,14 @@ await app.RunAsync(async (CoconaAppContext ctx) =>
{
await TrySendCommand(fiatClient, FiatCommand.DEEPREFRESH, vehicle.Vin);
}
-
+
if (appConfig.AutoRefreshLocation)
{
await TrySendCommand(fiatClient, FiatCommand.VF, vehicle.Vin);
}
-
+
await Task.Delay(TimeSpan.FromSeconds(10), ctx.CancellationToken);
-
+
var vehicleName = string.IsNullOrEmpty(vehicle.Nickname) ? "Car" : vehicle.Nickname;
var suffix = appConfig.DevMode ? "DEV" : "";
@@ -77,43 +90,84 @@ await app.RunAsync(async (CoconaAppContext ctx) =>
Lon = vehicle.Location.Longitude
};
+ Log.Debug("Announce sensor: {0}", tracker.Dump());
await tracker.Announce();
await tracker.PublishState();
var compactDetails = vehicle.Details.Compact("car");
- await Parallel.ForEachAsync(compactDetails, async (sensorData, token) =>
+ var sensors = compactDetails.Select(detail =>
{
- var sensor = new HaSensor(mqttClient, sensorData.Key, haDevice)
+ var sensor = new HaSensor(mqttClient, detail.Key, haDevice)
{
- Value = sensorData.Value
+ Value = detail.Value
};
-
+
+ if (detail.Key.EndsWith("_value"))
+ {
+ var unitKey = detail.Key.Replace("_value", "_unit");
+
+ compactDetails.TryGetValue(unitKey, out var tmpUnit);
+
+ if (appConfig.ConvertKmToMiles && tmpUnit == "km")
+ {
+ if (int.TryParse(detail.Value, out var kmValue))
+ {
+ var miValue = kmValue * 0.62137;
+ sensor.Value = miValue.ToString(CultureInfo.InvariantCulture);
+ tmpUnit = "mi";
+ }
+ }
+
+ switch (tmpUnit)
+ {
+ case "volts":
+ sensor.Icon = "mdi:lightning-bolt";
+ sensor.Unit = "V";
+ break;
+ case null or "null":
+ sensor.Unit = "";
+ break;
+ default:
+ sensor.Unit = tmpUnit;
+ break;
+ }
+ }
+
+ return sensor;
+ });
+
+ await Parallel.ForEachAsync(sensors.ToList(), async (sensor, token) =>
+ {
+ Log.Debug("Announce sensor: {0}", sensor.Dump());
await sensor.Announce();
await sensor.PublishState();
});
- var haEntities = persistentHaEntities.GetOrAdd(vehicle.Vin, s =>
- CreateEntities(fiatClient, mqttClient, vehicle, haDevice));
+ var haEntities = persistentHaEntities.GetOrAdd(vehicle.Vin, s =>
+ CreateInteractiveEntities(fiatClient, mqttClient, vehicle, haDevice));
foreach (var haEntity in haEntities)
{
+ Log.Debug("Announce sensor: {0}", haEntity.Dump());
await haEntity.Announce();
}
}
}
catch (FlurlHttpException httpException)
{
- Console.WriteLine($"Error connecting to the FIAT API. \n" +
- $"This can happen from time to time. Retrying in {appConfig.RefreshInterval} minutes.");
+ Log.Warning($"Error connecting to the FIAT API. \n" +
+ $"This can happen from time to time. Retrying in {appConfig.RefreshInterval} minutes.");
- httpException.Message.Dump();
+ Log.Debug("{0}", httpException.Message);
}
catch (Exception e)
{
- Console.WriteLine(e.Message);
+ Log.Error("{0}", e);
}
+ Log.Information("Fetching COMPLETED. Next update in {0} minutes.", appConfig.RefreshInterval);
+
WaitHandle.WaitAny(new[]
{
ctx.CancellationToken.WaitHandle,
@@ -122,16 +176,16 @@ await Parallel.ForEachAsync(compactDetails, async (sensorData, token) =>
}
});
-async Task TrySendCommand(FiatClient fiatClient, FiatCommand command, string vin)
+async Task TrySendCommand(IFiatClient fiatClient, FiatCommand command, string vin)
{
- Console.WriteLine($"SEND COMMAND: {command.Message}");
+ Log.Information("SEND COMMAND {0}: ", command.Message);
var pin = appConfig.FiatPin ?? throw new Exception("PIN NOT SET");
if (command.IsDangerous && !appConfig.EnableDangerousCommands)
{
- Console.WriteLine($"{command.Message} not sent. " +
- "Set \"EnableDangerousCommands\" option if you want to use it.");
+ Log.Warning("{0} not sent. " +
+ "Set \"EnableDangerousCommands\" option if you want to use it. ", command.Message);
return false;
}
@@ -139,19 +193,20 @@ async Task TrySendCommand(FiatClient fiatClient, FiatCommand command, stri
{
await fiatClient.SendCommand(vin, command.Message, pin, command.Action);
await Task.Delay(TimeSpan.FromSeconds(5));
- Console.WriteLine($"COMMAND: {command.Message} SUCCESSFUL");
+ Log.Information("Command: {0} SUCCESSFUL", command.Message);
}
catch (Exception e)
{
- Console.WriteLine($"Error sending command: {command.Message}. Maybe wrong pin?");
- e.Message.Dump();
+ Log.Error("Command: {0} ERROR. Maybe wrong pin?", command.Message);
+ Log.Debug("{0}", e);
return false;
}
return true;
}
-IEnumerable CreateEntities(FiatClient fiatClient, SimpleMqttClient mqttClient, Vehicle vehicle, HaDevice haDevice)
+IEnumerable CreateInteractiveEntities(IFiatClient fiatClient, SimpleMqttClient mqttClient, Vehicle vehicle,
+ HaDevice haDevice)
{
var updateLocationButton = new HaButton(mqttClient, "UpdateLocation", haDevice, async button =>
{
@@ -189,6 +244,14 @@ IEnumerable CreateEntities(FiatClient fiatClient, SimpleMqttClient mqt
forceLoopResetEvent.Set();
});
+ var lockSwitch = new HaSwitch(mqttClient, "DoorLock", haDevice, async sw =>
+ {
+ if (await TrySendCommand(fiatClient, sw.IsOn ? FiatCommand.RDL : FiatCommand.RDU, vehicle.Vin))
+ forceLoopResetEvent.Set();
+ });
+
return new HaEntity[]
- { hvacSwitch, trunkSwitch, chargeNowButton, deepRefreshButton, locateLightsButton, updateLocationButton };
+ {
+ hvacSwitch, trunkSwitch, chargeNowButton, deepRefreshButton, locateLightsButton, updateLocationButton, lockSwitch
+ };
}
\ No newline at end of file
diff --git a/FiatChampAddon/FiatClient/SimpleMqttClient.cs b/FiatChampAddon/FiatClient/SimpleMqttClient.cs
index b15e171..ad10b4b 100644
--- a/FiatChampAddon/FiatClient/SimpleMqttClient.cs
+++ b/FiatChampAddon/FiatClient/SimpleMqttClient.cs
@@ -2,6 +2,7 @@
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Protocol;
+using Serilog;
namespace FiatChamp;
@@ -61,7 +62,7 @@ public async Task Sub(string topic, Func callback)
}
catch (Exception e)
{
- Console.WriteLine(e);
+ Log.Error("{0}", e);
}
}
};
diff --git a/FiatChampAddon/config.yaml b/FiatChampAddon/config.yaml
index 469b41d..5bec142 100644
--- a/FiatChampAddon/config.yaml
+++ b/FiatChampAddon/config.yaml
@@ -3,7 +3,7 @@ url: "https://github.com/wubbl0rz/FiatChamp"
description: "Connect your FIAT (uconnect) car to Home Assistant. 🚗"
services:
- "mqtt:need"
-version: "2.0.6"
+version: "2.0.13"
image: "ghcr.io/wubbl0rz/image-{arch}-fiat-champ"
slug: "fiat_champ"
init: false
@@ -14,6 +14,7 @@ options:
FiatPw: ""
FiatPin: ""
RefreshInterval: 15
+ ConvertKmToMiles: false
Debug: false
AutoRefreshBattery: false
AutoRefreshLocation: false
@@ -22,6 +23,7 @@ schema:
FiatUser: str
FiatPw: password
FiatPin: password?
+ ConvertKmToMiles: bool
RefreshInterval: int
Debug: bool
AutoRefreshBattery: bool
diff --git a/FiatChampAddon/run.sh b/FiatChampAddon/run.sh
index fd3b8c8..ff98fde 100644
--- a/FiatChampAddon/run.sh
+++ b/FiatChampAddon/run.sh
@@ -9,11 +9,13 @@ export FiatChamp_FiatUser=$(bashio::config 'FiatUser')
export FiatChamp_FiatPw=$(bashio::config 'FiatPw')
export FiatChamp_FiatPin=$(bashio::config 'FiatPin')
+export FiatChamp_ConvertKmToMiles=$(bashio::config 'ConvertKmToMiles')
+
export FiatChamp_AutoRefreshLocation=$(bashio::config 'AutoRefreshLocation')
export FiatChamp_AutoRefreshBattery=$(bashio::config 'AutoRefreshBattery')
export FiatChamp_EnableDangerousCommands=$(bashio::config 'EnableDangerousCommands')
-DEBUG=$(bashio::config 'Debug')
+export FiatChamp_Debug=$(bashio::config 'Debug')
cd /build/
-./FiatChamp
\ No newline at end of file
+./FiatChamp
diff --git a/FiatChampAddon/translations/en.yaml b/FiatChampAddon/translations/en.yaml
index 3508fcd..8dd0b53 100644
--- a/FiatChampAddon/translations/en.yaml
+++ b/FiatChampAddon/translations/en.yaml
@@ -9,9 +9,15 @@ configuration:
FiatPin:
name: Pin
description: Your PIN. Used for sending commands to the car.
+ ConvertKmToMiles:
+ name: Convert km to miles (EXPERIMENTAL)
+ description: Try to convert kilometer values to miles
RefreshInterval:
name: Refresh interval
description: Fetch new data from api every N minutes.
+ Debug:
+ name: Debug
+ description: Enable debug logging. It will dump many informations to the log including session tokens and sensitive informations.
EnableDangerousCommands:
name: Dangerous commands.
description: Enable commands that are potentially dangerous and/or experimental. Like unlocking doors or deactivate air conditioning.
diff --git a/build.sh b/build.sh
index 0b5d700..69283da 100755
--- a/build.sh
+++ b/build.sh
@@ -1,11 +1,8 @@
#!/usr/bin/env bash
-cd FiatChampAddon/FiatClient/
+cp README.md FiatChampAddon/DOCS.md
+cp README.md FiatChampAddon/.
-~/.dotnet/dotnet publish --configuration Release -r linux-musl-x64 --self-contained=true -o build/amd64
-~/.dotnet/dotnet publish --configuration Release -r linux-musl-arm --self-contained=true -o build/armv7
+VERSION=$(cat FiatChampAddon/config.yaml| grep version | grep -P -o "[\d\.]*")
-cd ../../
-
-docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
-docker run --rm --privileged -v ~/.docker:/root/.docker -v $(pwd)/FiatChampAddon:/data homeassistant/amd64-builder --all -t /data
+git tag -a $VERSION -m $VERSION