Skip to content

Commit

Permalink
Merge pull request #12 from KornSW/v.1.2.4
Browse files Browse the repository at this point in the history
V.1.2.4
  • Loading branch information
DNAngelX authored Apr 24, 2023
2 parents 6024729 + 6cbe2b2 commit 50f776f
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 40 deletions.
41 changes: 37 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,52 @@ I started this project because I needed it myself. In order to be able to offer
## API-Versions

Within the config dialog you can enable the support for the breaking changes that were suddenly made to the API.
To do so, just enter "**gen-2**" instead of "**default**". The Adapter will follow the new communication contract,
wich is actually a **BETA-FEATURE**!
Please feel free to help us getting this stable - its tracked here: [Issue #6](https://github.com/KornSW/ioBroker.fusionsolar/issues/6) (german)

## Call Limits & Settings

![image](doc/UI-Fusion.png)
We added two new functions regarding API Limitations and #407 API Errors.

* Main Setting - **Retry API call: if there is a call limit (#407)**
* Device Objects - **Loading frequency per device**

The **Retry API call: if there is a call limit (#407)** function will not skip the calls anymore, if the API will give an Call Limit issue back. We try with this function to load the data, until we are getting *success* (Before we skipped that call).

Every Device has now a **Loading frequency per device** state where you can set the Loading frequency.

##### Example
![image](doc/updatePrioritySetting.png)

In you Adapter Setting you have *60* Seconds in your **Abfrageintervall in Sekunden** and *15* in your **Wartezeit zwischen API-Anfragen in Sekunden**.
This means, the Adapter will initiate the requests from Huawai every **60** seconds and will make a break after every API call for **15** Seconds.

Usually we loaded all devices here.

You can set now in every device a Level with the following settings:

|ID|Level|Info|Explaination|
|--|--|--|--|
|0|don't update||After init call, it will never update this device again|
|1|Level 1|every time|Calls this device every 60 sec. *|
|2|Level 2|every 2nd time|Calls this device every 120 sec. *|
|3|Level 3|every 4th time|Calls this device every 240 sec. *|
|4|Level 4|every 8th time|Calls this device every 480 sec. *|
|5|Level 5|every 16th time|Calls this device every 960 sec. *|
|6|Level 6|every 32thtime|Calls this device every 1920 sec. *|

\* after a finished complete loop.

## @Huawei

Unfortunately i have to say that the api feels relatively unstable. Above all, dealing with the numerous quota restrictions and different error endings can only be managed by senior developers. I hope that this is not an experiment, and that you will continue to further develop the api. Otherwise my work was unfortunately in vain. There is a large community with the need of a working api.
It would also be nice, if you could check why the returned values sometimes deviate from those in your app (sometimes so much that it cannot be a matter of a time lag).

## Changelog

### 1.2.4
* (Stolly82) API Call Limit Optimization",
### 1.2.3
* (KornSW) (beta-)support for new API-version",
* (KornSW) support for new API-version",
### 1.1.0
* (KornSW) Opt-in for loading data of 'optimizers' or unknown devices (to reduce api load)",
### 1.0.1
Expand Down
5 changes: 5 additions & 0 deletions admin/index_m.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,12 @@ <h6 class="title translate">Api settings</h6>
<input type="checkbox" class="value" id="skipUnknownDevices" />
<label for="skipUnknownDevices">Skip devices of unknown type</label>
</div>
<div class="col s6 input-field">
<input type="checkbox" class="value" id="apiRetry" />
<label for="apiRetry">Retry API call: if there is a call limit (#407)</label>
</div>
</div>

<div class="row">
<div class="col s6 input-field">
<select id="apiVersion" class="value">
Expand Down
Binary file added doc/UI-Fusion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/updatePrioritySetting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 9 additions & 4 deletions io-package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
{
"common": {
"name": "fusionsolar",
"version": "1.2.3",
"version": "1.2.4",
"news": {
"1.2.4": {
"en": "API Call Limit Optimization",
"de": "API Call- Limit Optimierung"
},
"1.2.3": {
"en": "(beta-)support for new API-version",
"de": "(beta-)Support für neue API-Version"
"en": "support for new API-version",
"de": "Support für neue API-Version"
},
"1.1.0": {
"en": "Opt-in for loading data of 'optimizers' or unknown devices (to reduce api load)",
Expand Down Expand Up @@ -80,7 +84,8 @@
"timeslotlength": 3,
"skipOptimizers": true,
"skipUnknownDevices": true,
"apiVersion": "default"
"apiVersion": "default",
"apiRetry": true
},
"objects": [],
"instanceObjects": [
Expand Down
110 changes: 79 additions & 31 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,24 @@ let stationList = [];
let deviceList = [];
let accessToken = '';
let loggedIn = false;
let myStation = '';
let deviceId = '';

// ### WILL BE SYNCED FROM SETTINGS #######
let polltime = 180;
let timeslotlength = 3;
let skipOptimizers = true;
let skipUnknownDevices = true;
let apiVersion = 'default';
let apiRetry = true;
// ########################################

//the array-index is the priority level
//semantic of the array-values: participate on the update every {x} iterations
const frequenciesPerPriority = [0, 1, 5, 15, 50];
const frequenciesPerPriority = [0,1,2,4,8,16,32]; // every x count it will crawl
let globalIterationCounter = 0;


class FusionSolarConnector extends utils.Adapter {

/**
Expand Down Expand Up @@ -68,6 +72,7 @@ class FusionSolarConnector extends utils.Adapter {
}
skipOptimizers = this.config.skipOptimizers;
skipUnknownDevices = this.config.skipUnknownDevices;
apiRetry = this.config.apiRetry;

apiVersion = this.config.apiVersion;
if (apiVersion == 'default') {
Expand Down Expand Up @@ -159,6 +164,8 @@ class FusionSolarConnector extends utils.Adapter {
this.log.debug('writing station related channel values...');
this.writeStationDataToIoBrokerStates(stationInfo, stationRealtimeKpiData, (isFirsttimeInit || errorCounter > 0));
});

myStation = stationInfo.stationCode;

if(isFirsttimeInit) {
this.log.debug('initially loading DeviceList for ' + stationInfo.stationCode + ' from the API...');
Expand All @@ -172,6 +179,8 @@ class FusionSolarConnector extends utils.Adapter {
this.log.debug('writing station related channel values...');
this.writeStationDataToIoBrokerStates(stationInfo, stationRealtimeKpiData, (isFirsttimeInit || errorCounter > 0));
});

myStation = stationInfo.plantCode;

if(isFirsttimeInit) {
this.log.debug('initially loading DeviceList for ' + stationInfo.plantCode + ' from the API...');
Expand All @@ -182,37 +191,43 @@ class FusionSolarConnector extends utils.Adapter {

if(deviceList){
for(const deviceInfo of deviceList) {

deviceId = deviceInfo.id;

let deviceRelatedUpdatePriority = 0;
if(deviceInfo.devTypeId == 1){
//INVERTER
deviceRelatedUpdatePriority = 1;
}
else if(deviceInfo.devTypeId == 62){
//DONGLE
deviceRelatedUpdatePriority = 4;
}
else if(deviceInfo.devTypeId == 46){
//OPTIMIZER
if(skipOptimizers) continue;
}
else if(deviceInfo.devTypeId == 47){
//METER
deviceRelatedUpdatePriority = 1;
}
else if(deviceInfo.devTypeId == 39){
//BATTERY
deviceRelatedUpdatePriority = 2;
}
else {
//UNKNOWN
if(skipUnknownDevices) continue;
}

//TODO: here the deviceRelatedUpdatePriority shloud be loaded from the ioBroker channel
//to allow individual adjustment by the user...
//when implementin this, the hardcoded values above can be removed in order with
//a propper initialization of defaults when creating the ioBroker channels

deviceRelatedUpdatePriority = await this.getStateAsync(myStation + '.' + deviceId + '.' + 'updatePriority');


if (deviceRelatedUpdatePriority == null || deviceRelatedUpdatePriority == undefined)
{
deviceRelatedUpdatePriority = 1;
this.log.debug('Level for '+ deviceId + ' Loaded by default: ' + deviceRelatedUpdatePriority);
} else {
deviceRelatedUpdatePriority = deviceRelatedUpdatePriority.val;
}

this.log.debug('Level for '+ deviceId + ' Loaded - : ' + deviceRelatedUpdatePriority);

const freq = frequenciesPerPriority[deviceRelatedUpdatePriority];
if(freq <= 0){
Expand Down Expand Up @@ -289,10 +304,10 @@ class FusionSolarConnector extends utils.Adapter {

async writeChannelDataToIoBroker(channelParentPath, channelName, value, channelType, channelRole, createObjectInitally, createObjectInitallyUnit, createObjectInitallyStates) {
if(channelParentPath != null){
channelParentPath = channelParentPath + '.';
channelParentPath = channelParentPath;
}
if(createObjectInitally && createObjectInitallyUnit){
await this.setObjectNotExistsAsync(channelParentPath + channelName, {
await this.setObjectNotExistsAsync(channelParentPath + '.' + channelName, {
type: 'state',
common: {
name: channelName,
Expand All @@ -306,20 +321,20 @@ class FusionSolarConnector extends utils.Adapter {
});
} else if(createObjectInitally && createObjectInitallyStates){
//createObjectInitallyStates = {"2": "Entladen", "1": "BLA"}
await this.setObjectNotExistsAsync(channelParentPath + channelName, {
await this.setObjectNotExistsAsync(channelParentPath + '.' + channelName, {
type: 'state',
common: {
name: channelName,
type: channelType,
role: channelRole,
states: createObjectInitallyStates,
read: true,
write: false,
write: true,
},
native: {},
});
} else if(createObjectInitally){
await this.setObjectNotExistsAsync(channelParentPath + channelName, {
await this.setObjectNotExistsAsync(channelParentPath + '.' + channelName, {
type: 'state',
common: {
name: channelName,
Expand All @@ -330,9 +345,16 @@ class FusionSolarConnector extends utils.Adapter {
},
native: {},
});
await this.setObjectNotExistsAsync(channelParentPath, {
type: 'channel',
common: {
name: channelParentPath
},
native: {},
});
}
if(value != undefined){
await this.setStateAsync(channelParentPath + channelName, value, true);
if(value != undefined || value != null){
await this.setStateAsync(channelParentPath + '.' + channelName, value, true);
}
}

Expand Down Expand Up @@ -433,13 +455,15 @@ class FusionSolarConnector extends utils.Adapter {
//await this.writeChannelDataToIoBroker(deviceFolder, 'stationCode', deviceInfo.stationCode, 'string', 'indicator', createObjectsInitally);

const updateupdatePrioritySelection = {
0: 'dont update',
1: 'Priority 1',
2: 'Priority 2',
3: 'Priority 3',
4: 'Priority 4'
0:"don't update",
1:"Level 1 (every time)",
2:"Level 2 (every 2nd time)",
3:"Level 3 (every 4th time)",
4:"Level 4 (every 8th time)",
5:"Level 5 (every 16th time)",
6:"Level 6 (every 32th time)"
};
await this.writeChannelDataToIoBroker(deviceFolder, 'updatePriority', 1, 'number', 'indicator', createObjectsInitally, null, updateupdatePrioritySelection);
await this.writeChannelDataToIoBroker(deviceFolder, 'updatePriority', null, 'number', 'indicator', createObjectsInitally, null, updateupdatePrioritySelection);
await this.writeChannelDataToIoBroker(deviceFolder, 'lastUpdate', new Date().toLocaleTimeString(), 'string', 'indicator', createObjectsInitally);

if(deviceRealtimeKpiData) {
Expand Down Expand Up @@ -716,8 +740,14 @@ class FusionSolarConnector extends utils.Adapter {
return null;
}
else if(response.data.failCode == 407){
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return null;
if (apiRetry)
{
this.log.debug('API returned failCode #407 (access frequency is too high) - I will give their API another chance!');
return retry;
} else {
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return {};
}
}
else if(response.data.failCode == 401){
this.log.error('API returned failCode #401 (invalid access to current interface) - MAY BE A MISSMATCH OF THE API-VERSION!');
Expand Down Expand Up @@ -824,8 +854,14 @@ class FusionSolarConnector extends utils.Adapter {
return {};
}
else if(response.data.failCode == 407){
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return {};
if (apiRetry)
{
this.log.debug('API returned failCode #407 (access frequency is too high) - I will give their API another chance!');
return retry;
} else {
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return {};
}
}
else if(response.data.failCode > 0){
this.log.error('API returned failCode #' + response.data.failCode);
Expand Down Expand Up @@ -894,8 +930,14 @@ class FusionSolarConnector extends utils.Adapter {
return null;
}
else if(response.data.failCode == 407){
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return null;
if (apiRetry)
{
this.log.debug('API returned failCode #407 (access frequency is too high) - I will give their API another chance!');
return retry;
} else {
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return {};
}
}
else if(response.data.failCode > 0){
this.log.error('API returned failCode #' + response.data.failCode);
Expand Down Expand Up @@ -1001,8 +1043,14 @@ class FusionSolarConnector extends utils.Adapter {
return {};
}
else if(response.data.failCode == 407){
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return {};
if (apiRetry)
{
this.log.debug('API returned failCode #407 (access frequency is too high) - I will give their API another chance!');
return retry;
} else {
this.log.error('API returned failCode #407 (access frequency is too high) - giving up now :-(');
return {};
}
}
else if(response.data.failCode > 0){
this.log.error('API returned failCode #' + response.data.failCode);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "iobroker.fusionsolar",
"version": "1.2.3",
"version": "1.2.4",
"description": "Adapter to connect Huawei FusionSolar API",
"author": {
"name": "KornSW",
Expand Down

0 comments on commit 50f776f

Please sign in to comment.