Skip to content

Commit

Permalink
Add work mode support + update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
dmarjoram committed Jul 20, 2022
1 parent 83b2ab6 commit 6aabd93
Show file tree
Hide file tree
Showing 9 changed files with 438 additions and 18 deletions.
2 changes: 2 additions & 0 deletions Configuration/FoxESSConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ public class FoxESSConfiguration
public string? Username { get; set; }

public string? PasswordMD5Hash { get; set; }

public Guid? CloudDeviceId { get; set; }
}
}
47 changes: 47 additions & 0 deletions Controllers/FoxESSController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Roses.SolarAPI.Configuration;
using Roses.SolarAPI.Models;
using Roses.SolarAPI.Models.FoxCloud;
using Roses.SolarAPI.Services;

namespace Roses.SolarAPI.Controllers
Expand Down Expand Up @@ -66,5 +67,51 @@ public async Task<ApiResult> FoxCloudDisableForceChargeTimePeriod1(CancellationT
ResultCode = await _foxESSService.FoxCloudDisableForceChargeTimePeriod1(ct)
};
}

[HttpGet]
[Route("Cloud/DeviceList")]
public Task<Device[]> GetDeviceList(CancellationToken ct)
{
return _foxESSService.GetDeviceList(ct);
}

/// <summary>
/// Set inverter for feed-in
/// </summary>
[HttpPost]
[Route("Cloud/WorkMode/FeedIn")]
public async Task<ApiResult> FoxCloudSetWorkModeFeedIn(CancellationToken ct = default)
{
return new ApiResult()
{
ResultCode = await _foxESSService.FoxCloudSetWorkModeFeedIn(ct)
};
}

/// <summary>
/// Set inverter for self-use
/// </summary>
[HttpPost]
[Route("Cloud/WorkMode/SelfUse")]
public async Task<ApiResult> FoxCloudSetWorkModeSelfUse(CancellationToken ct = default)
{
return new ApiResult()
{
ResultCode = await _foxESSService.FoxCloudSetWorkModeSelfUse(ct)
};
}

/// <summary>
/// Set inverter for backup
/// </summary>
[HttpPost]
[Route("Cloud/WorkMode/Backup")]
public async Task<ApiResult> FoxCloudSetWorkModeBackup(CancellationToken ct = default)
{
return new ApiResult()
{
ResultCode = await _foxESSService.FoxCloudSetWorkModeBackup(ct)
};
}
}
}
35 changes: 35 additions & 0 deletions Models/FoxCloud/DeviceListRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Text.Json.Serialization;

namespace Roses.SolarAPI.Models.FoxCloud
{
public partial class DeviceListRequest
{
[JsonPropertyName("pageSize")]
public int PageSize { get; set; } = 10;

[JsonPropertyName("currentPage")]
public int CurrentPage { get; set; } = 1;

[JsonPropertyName("total")]
public int Total { get; set; } = 0;

[JsonPropertyName("condition")]
public Condition Condition { get; set; } = new Condition();
}

public partial class Condition
{
[JsonPropertyName("queryDate")]
public QueryDate QueryDate { get; set; } = new QueryDate();
}

public partial class QueryDate
{
[JsonPropertyName("begin")]
public int Begin { get; set; } = 0;

[JsonPropertyName("end")]
public int End { get; set; } = 0;
}

}
82 changes: 82 additions & 0 deletions Models/FoxCloud/DeviceListResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.Text.Json.Serialization;

namespace Roses.SolarAPI.Models.FoxCloud
{
public partial class DeviceListResponse : IFoxResponse
{
[JsonPropertyName("errno")]
public int Errno { get; set; }

[JsonPropertyName("result")]
public Result? Result { get; set; }
}

public partial class Result
{
[JsonPropertyName("currentPage")]
public int CurrentPage { get; set; }

[JsonPropertyName("pageSize")]
public int PageSize { get; set; }

[JsonPropertyName("total")]
public int Total { get; set; }

[JsonPropertyName("devices")]
public Device[]? Devices { get; set; }
}

public partial class Device
{
[JsonPropertyName("deviceID")]
public Guid DeviceId { get; set; }

[JsonPropertyName("deviceSN")]
public string? DeviceSn { get; set; }

[JsonPropertyName("moduleSN")]
public string? ModuleSn { get; set; }

[JsonPropertyName("plantName")]
public string? PlantName { get; set; }

[JsonPropertyName("deviceType")]
public string? DeviceType { get; set; }

[JsonPropertyName("country")]
public string? Country { get; set; }

[JsonPropertyName("countryCode")]
public string? CountryCode { get; set; }

[JsonPropertyName("feedinDate")]
public string? FeedinDate { get; set; }

[JsonPropertyName("status")]
public int Status { get; set; }

[JsonPropertyName("power")]
public double Power { get; set; }

[JsonPropertyName("generationToday")]
public double GenerationToday { get; set; }

[JsonPropertyName("generationTotal")]
public double GenerationTotal { get; set; }

[JsonPropertyName("productType")]
public string? ProductType { get; set; }

[JsonPropertyName("flowType")]
public int FlowType { get; set; }

[JsonPropertyName("hasBattery")]
public bool HasBattery { get; set; }

[JsonPropertyName("hasPV")]
public bool HasPv { get; set; }

[JsonPropertyName("dataLatestUploadDate")]
public string? DataLatestUploadDate { get; set; }
}
}
4 changes: 2 additions & 2 deletions Models/FoxCloud/LoginResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Roses.SolarAPI.Models.FoxCloud
{
public class Result
public class LoginResult
{
[JsonPropertyName("token")]
public string? Token { get; set; }
Expand All @@ -21,6 +21,6 @@ public class LoginResponse : IFoxResponse
public int Errno { get; set; } = (int)FoxErrorNumber.NoResponse;

[JsonPropertyName("result")]
public Result? Result { get; set; }
public LoginResult? Result { get; set; }
}
}
49 changes: 49 additions & 0 deletions Models/FoxCloud/SetWorkModeRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Text.Json.Serialization;

namespace Roses.SolarAPI.Models.FoxCloud
{
public partial class SetWorkModeRequest : IFoxRequest
{
[JsonPropertyName("id")]
public Guid Id { get; set; }

[JsonPropertyName("key")]
public string? Key { get; set; } = "h106__02__00";

[JsonPropertyName("values")]
public Values? Values { get; set; } = new Values();

public void Validate()
{
if (Id == Guid.Empty)
{
throw new ArgumentNullException(nameof(SetWorkModeRequest), "No cloud device ID is provided.");
}

if (string.IsNullOrWhiteSpace(Key))
{
throw new ArgumentOutOfRangeException(nameof(SetWorkModeRequest), "Key has been changed.");
}

if (!WorkModes.ALL.Any(mode => mode == Values?.Mode))
{
throw new ArgumentOutOfRangeException(nameof(SetWorkModeRequest), "A valid work mode has not been provided.");
}
}
}

public partial class Values
{
[JsonPropertyName("h106__02__00")]
public string? Mode { get; set; }
}

public class WorkModes
{
public const string FEED_IN = "Feedin";
public const string SELF_USE = "SelfUse";
public const string BACKUP = "Backup";

public readonly static string[] ALL = new[] { FEED_IN, SELF_USE, BACKUP };
}
}
20 changes: 20 additions & 0 deletions Models/FoxCloud/SetWorkModeResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Roses.SolarAPI.Services;
using System.Text.Json.Serialization;

namespace Roses.SolarAPI.Models.FoxCloud
{
public class SetWorkModeResponse : IFoxResponse
{
/// <summary>
/// 41808 means token is invalid
/// 40257 means invalid request param
/// 41203 means timeout
/// 0 means OK
/// </summary>
[JsonPropertyName("errno")]
public int Errno { get; set; } = (int)FoxErrorNumber.NoResponse;

[JsonPropertyName("result")]
public object? Result { get; set; }
}
}
44 changes: 37 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,68 @@ docker pull drosedev/rosessolarapi
| FOXESSCONFIGURATION__IPADDRESS | addme | The IP address on the LAN for local USR device. Currently not used to set battery charging. |
| FOXESSCONFIGURATION__USERNAME| addme| Your FoxCloud username |
| FOXESSCONFIGURATION__PASSWORDMD5HASH | addme1234567890addme | Lower-case MD5 hash of your FoxCloud password |
| FOXESSCONFIGURATION__SERIALNUMBER | 66xxxxaddme| Your Fox inverter serial number (required for FoxCloud battery API calls) |
| FOXESSCONFIGURATION__SERIALNUMBER | 66xxxxaddme| OPTIONAL - Your Fox inverter serial number (required for FoxCloud battery API calls). **Providing this speedsup API calls as we don't have to internally read the device list from the cloud**) |
| FOXESSCONFIGURATION__CLOUDDEVICEID | a234567a-dabc-4510-1234-e61ac52f4dv2 | OPTIONAL - Your Fox inverter device ID GUID from the address bar of Fox Cloud portal (required for FoxCloud battery API calls). **Providing this speedsup API calls as we don't have to internally read the device list from the cloud**) |
| TZ | Europe/London | Required so force charging starts at the correct local time |

Internal to the container the service runs on port 80. You can map this internal port to whatever you want with bridged networking on your Docker host.

# Example calls
### Using FoxCloud
Force charge (stop discharge) but don't charge from grid (from now until 23:59)
`POST http://192.168.0.5:8200/FoxESS/Cloud/ForceChargeForTodayTimePeriod1?enableGridCharging=false`
`POST http://dockerhost-ip:mappedport/FoxESS/Cloud/ForceChargeForTodayTimePeriod1?enableGridCharging=false`

Force charge now from grid (from now until 23:59)
`POST http://192.168.0.5:8200/FoxESS/Cloud/ForceChargeForTodayTimePeriod1?enableGridCharging=true`
`POST http://dockerhost-ip:mappedport/FoxESS/Cloud/ForceChargeForTodayTimePeriod1?enableGridCharging=true`

Stop force charging
`POST http://192.168.0.5:8200/FoxESS/Cloud/DisableForceChargeTimePeriod1`
`POST http://dockerhost-ip:mappedport/FoxESS/Cloud/DisableForceChargeTimePeriod1`

Work Mode
`POST http://dockerhost-ip:mappedport/FoxESS/Cloud/WorkMode/SelfUse`
`POST http://dockerhost-ip:mappedport/FoxESS/Cloud/WorkMode/Backup`
`POST http://dockerhost-ip:mappedport/FoxESS/Cloud/WorkMode/FeedIn`

### Using modbus
Query battery status using RS485 device
`GET http://192.168.0.5:8200/FoxEss/Local/BatteryConfiguration`
`GET http://dockerhost-ip:mappedport/FoxEss/Local/BatteryConfiguration`

# Home Assistant
### configuration.yml

# Control of FOX ESS battery via Roses.SolarAPI (currently using FoxCloud)
rest_command:
fox_force_charge_now:
url: http://192.168.0.5:8200/FoxESS/Cloud/ForceChargeForTodayTimePeriod1?enableGridCharging=false
url: http://dockerhost-ip:mappedport/FoxESS/Cloud/ForceChargeForTodayTimePeriod1?enableGridCharging=false
method: POST
headers:
accept: "application/json"
user-agent: 'Mozilla/5.0 {{ useragent }}'
fox_force_charge_stop:
url: http://192.168.0.5:8200/FoxESS/Cloud/DisableForceChargeTimePeriod1
url: http://dockerhost-ip:mappedport/FoxESS/Cloud/DisableForceChargeTimePeriod1
method: POST
headers:
accept: "application/json"
user-agent: 'Mozilla/5.0 {{ useragent }}'

fox_workmode_selfuse:
url: http://dockerhost-ip:mappedport/FoxESS/Cloud/WorkMode/SelfUse
method: POST
headers:
accept: "application/json"
user-agent: 'Mozilla/5.0 {{ useragent }}'

fox_workmode_backup:
url: http://dockerhost-ip:mappedport/FoxESS/Cloud/WorkMode/Backup
method: POST
headers:
accept: "application/json"
user-agent: 'Mozilla/5.0 {{ useragent }}'

fox_workmode_feedin:
url: http://dockerhost-ip:mappedport/FoxESS/Cloud/WorkMode/FeedIn
method: POST
headers:
accept: "application/json"
user-agent: 'Mozilla/5.0 {{ useragent }}'
Loading

0 comments on commit 6aabd93

Please sign in to comment.