Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge dev #17

Merged
merged 6 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ If you use two inverters, then connect to the second inverter and read the commu
* `port`: Inverter modbus port (default: 502)
* `modbusId`: Primary Modbus inverter id (default: 1)
* `modbusId2`: Secondary Modbus inverter id (default: 0)
* `updateInterval`: Fast update interval (default: 30 sec)
* `updateInterval`: Fast update interval (default: 20 sec)

## Changelog
<!--
Expand All @@ -55,15 +55,16 @@ If you use two inverters, then connect to the second inverter and read the commu
-->

### **WORK IN PROGRESS**
* (bolliy) Increase stability
* (bolliy) severeals states
prepare collected values more precisely

### 0.0.3 (2024-01-01)
### 0.1.1 (2024-01-07)
* fix some collected values

### 0.1.0 (2024-01-06)
* watchdog implemented #11
* state values are cached - only changed data should be stored
* derived and collected values for example `inputPowerEffective` or `inputYield`
* more states

* deploy more register
### 0.0.2 (2023-12-19)
Dependency and configuration updates

Expand Down
2 changes: 1 addition & 1 deletion admin/jsonConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"updateInterval": {
"type": "number",
"label": "Update interval (s)",
"default": 30,
"default": 20,
"newLine": true,
"tooltip": "Update interval to update the values from the inverters"
}
Expand Down
32 changes: 5 additions & 27 deletions io-package.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,11 @@
{
"common": {
"name": "sun2000",
"version": "0.0.2",
"version": "0.1.1",
"news": {
"0.0.1": {
"en": "initial release",
"de": "Erstveröffentlichung",
"ru": "Начальная версия",
"pt": "lançamento inicial",
"nl": "Eerste uitgave",
"fr": "Première version",
"it": "Versione iniziale",
"es": "Versión inicial",
"pl": "Pierwsze wydanie",
"uk": "початковий випуск",
"zh-cn": "初始发行"
},
"0.0.2": {
"en": "Dependency and configuration updates",
"de": "Abhängigkeits- und Konfigurationsupdates",
"ru": "В зависимости и обновления конфигурации",
"pt": "Atualizações de dependência e configuração",
"nl": "Afhankelijkheid en configuratie updates",
"fr": "Mise à jour de dépendance et de configuration",
"it": "Dipendenza e aggiornamenti di configurazione",
"es": "Actualizaciones de dependencia y configuración",
"pl": "Zależność i aktualizacja konfiguracji",
"uk": "Залежність та оновлення конфігурації",
"zh-cn": "B. 扶养和配置的最新情况"
"0.1.1": {
"en": "fix some collected values",
"de": "Korrektur einiger der gesammelten Werte (collected values)"
}
},
"titleLang": {
Expand Down Expand Up @@ -209,7 +187,7 @@
"type": "number",
"role": "value",
"read": true,
"write": true,
"write": false,
"desc": "modbus update interval",
"unit": "sec"
}
Expand Down
112 changes: 73 additions & 39 deletions lib/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ class StateMap {
return this.stateMap.get(id);
}

set(id, value, renew = false) {
set(id, value, options) {
if (options?.type == 'number' && isNaN(value)) return;
if (value !== null) {
if (renew || this.get(id)?.value !== value) {
this.stateMap.set(id, {id: id, value: value});
if (options?.renew || this.get(id)?.value !== value) {
if (options?.stored ) {
this.stateMap.set(id, {id: id, value: value, stored: options.stored});
} else {
this.stateMap.set(id, {id: id, value: value});
}
}
}
}
Expand All @@ -30,7 +35,7 @@ class Registers {
this.adapter = adapterInstance;
this.stateCache = new StateMap();

this.loadStates();
this._loadStates();

//https://www.iobroker.net/#de/documentation/basics/roles.md
this.registerFields = [
Expand All @@ -54,7 +59,7 @@ class Registers {
states : [{
state: {id: 'activePower', name: 'Active power', type: 'number', unit: 'kW', role: 'value.power', desc: 'Power currently used'},
register: {reg: 32080, type: dataType.int32, gain:1000},
storeAlways: true
storeAlways: false
}]
},
{
Expand All @@ -66,7 +71,7 @@ class Registers {
states : [{
state: {id: 'inputPower', name: 'Input power' , type: 'number', unit: 'kW', role: 'value.power', desc: 'Power from solar'},
register: {reg: 32064, type: dataType.int32, gain:1000},
storeAlways: true
storeAlways: false
},
{
state: {id: 'derived.inputPowerWithEfficiencyLoss', name: 'input power with efficiency loss', type: 'number', unit: 'kW', role: 'value.power', desc: ''}
Expand All @@ -90,7 +95,7 @@ class Registers {
inPowerEff *= 0.98;
}
//inputPower_with_efficiency_loss
this.stateCache.set(path+'derived.inputPowerWithEfficiencyLoss', inPowerEff);
this.stateCache.set(path+'derived.inputPowerWithEfficiencyLoss', inPowerEff, {type: 'number'});
}
},
{
Expand Down Expand Up @@ -456,12 +461,12 @@ class Registers {
this.postUpdateHooks = [
{
refresh : dataRefreshRate.low,
state: {id: 'derived.dailyPortalYield', name: 'Input Yield Today', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'daily yield displayed on the portal'},
state: {id: 'derived.dailyInputYield', name: 'Input Yield Today', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'daily yield displayed on the portal'},
fn : (path) => {
const disCharge = this.stateCache.get(path+'battery.currentDayDischargeCapacity')?.value;
const charge = this.stateCache.get(path+'battery.currentDayChargeCapacity')?.value;
const inputYield = Math.round((this.stateCache.get(path+'dailyEnergyYield')?.value + charge - disCharge)*100)/100;
!isNaN(inputYield) && this.stateCache.set(path+'derived.dailyPortalYield', inputYield);
this.stateCache.set(path+'derived.dailyInputYield', inputYield, {type: 'number'});
}
}
];
Expand All @@ -483,51 +488,80 @@ class Registers {
inPower += this.stateCache.get(inverter.path+'.inputPower')?.value;
inPowerEff += this.stateCache.get(inverter.path+'.derived.inputPowerWithEfficiencyLoss')?.value;
}
!isNaN(inPower) && this.stateCache.set('collected.inputPower',inPower,true);
!isNaN(inPowerEff) && this.stateCache.set('collected.inputPowerWithEfficiencyLoss',inPowerEff,true);
!isNaN(sum) && this.stateCache.set('collected.activePower',sum,true);
this.stateCache.set('collected.inputPower',inPower,{type: 'number', renew : true});
this.stateCache.set('collected.inputPowerWithEfficiencyLoss',inPowerEff,{type: 'number', renew : true});
this.stateCache.set('collected.activePower',sum,{type: 'number', renew : true});
sum -= this.stateCache.get('meter.activePower')?.value;
!isNaN(sum) && this.stateCache.set('collected.houseConsumption',sum,true);
this.stateCache.set('collected.houseConsumption',sum,{type: 'number', renew : true});
}

},
{
refresh : dataRefreshRate.low,
states : [
{id: 'collected.dailyEnergyYield', name: 'Daily Energy Yield', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'daily output yield of the inverters'},
{id: 'collected.dailyPortalYield', name: 'Input Yield Today', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'daily yield displayed on the portal'},
{id: 'collected.dailyInputYield', name: 'Input Yield Today', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'daily yield displayed on the portal'},
{id: 'collected.accumulatedEnergyYield', name: 'Accumulated Energy Yield', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.consumptionSum', name: 'Consumption Sum', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.gridExportSum', name: 'Grid Export Sum', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.gridImportSum', name: 'Grid Export Sum', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.consumptionStart', name: 'Consumption Start', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.gridExportStart', name: 'Grid Export Start Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.gridImportStart', name: 'Grid Export Start Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.consumptionStart', name: 'Consumption Start Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.gridExportToday', name: 'Grid Export Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.gridImportToday', name: 'Grid Import Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.consumptionToday', name: 'Consumption Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'}
{id: 'collected.gridImportToday', name: 'Grid Import Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.consumptionToday', name: 'Consumption Today', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.totalCharge', name: 'Total Charge of Battery', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.totalDischarge', name: 'Total Discharge of Battery', type: 'number', unit: 'kWh', role: 'value.power.consumption'},
{id: 'collected.currentDayChargeCapacity', name: 'Current Day Charge Capacity of Battery', type: 'number', unit: 'kWh', role: 'value.power.consumption' },
{id: 'collected.currentDayDischargeCapacity', name: 'Current Day Discharge Capacity of Battery', type: 'number', unit: 'kWh', role: 'value.power.consumption', desc: 'TBD' },
{id: 'collected.SOC', name: 'State of battery capacity', type: 'number', unit: '%', role: 'value.battery', desc: 'SOC'},
{id: 'collected.ratedCapacity', name: 'Rated of battery Capacity', type: 'number', unit: 'Wh', role: 'value.capacity'}
],
fn : (inverters) => {
let inYield = 0;
let outYield = 0;
let enYield = 0;
let charge = 0;
let disCharge = 0;
let totalDisCharge = 0;
let totalCharge = 0;
let ratedCap = 0;
let load = 0;
for (const inverter of inverters) {
outYield += this.stateCache.get(inverter.path+'.dailyEnergyYield')?.value;
inYield += this.stateCache.get(inverter.path+'.derived.dailyPortalYield')?.value;
inYield += this.stateCache.get(inverter.path+'.derived.dailyInputYield')?.value;
enYield += this.stateCache.get(inverter.path+'.accumulatedEnergyYield')?.value;
charge += this.stateCache.get(inverter.path+'.battery.currentDayChargeCapacity')?.value;
disCharge += this.stateCache.get(inverter.path+'.battery.currentDayDischargeCapacity')?.value;
totalCharge += this.stateCache.get(inverter.path+'.battery.totalCharge')?.value;
totalDisCharge += this.stateCache.get(inverter.path+'.battery.totalDischarge')?.value;
if (this.stateCache.get(inverter.path+'.battery.ratedCapacity')?.value > 0) {
load += this.stateCache.get(inverter.path+'.battery.ratedCapacity')?.value * this.stateCache.get(inverter.path+'.battery.SOC')?.value;
ratedCap += this.stateCache.get(inverter.path+'.battery.ratedCapacity')?.value;
}
}
!isNaN(outYield) && this.stateCache.set('collected.dailyEnergyYield',outYield);
!isNaN(inYield) && this.stateCache.set('collected.dailyPortalYield',inYield);
!isNaN(enYield) && this.stateCache.set('collected.accumulatedEnergyYield',enYield);
this.stateCache.set('collected.dailyEnergyYield',outYield, {type: 'number'});
this.stateCache.set('collected.dailyInputYield',inYield, {type: 'number'});
this.stateCache.set('collected.accumulatedEnergyYield',enYield, {type: 'number'});
const conSum = enYield + this.stateCache.get('meter.reverseActiveEnergy')?.value - this.stateCache.get('meter.positiveActiveEnergy')?.value;
!isNaN(conSum) && this.stateCache.set('collected.consumptionSum',conSum);
this.stateCache.set('collected.consumptionSum',conSum, {type: 'number'});
// compute export and import today
this.stateCache.set('collected.gridExportToday',this.stateCache.get('meter.positiveActiveEnergy')?.value - this.stateCache.get('collected.gridExportSum')?.value);
this.stateCache.set('collected.gridImportToday',this.stateCache.get('meter.reverseActiveEnergy')?.value - this.stateCache.get('collected.gridImportSum')?.value);
this.stateCache.set('collected.gridExportToday',this.stateCache.get('meter.positiveActiveEnergy')?.value -
this.stateCache.get('collected.gridExportStart')?.value, {type: 'number'});
this.stateCache.set('collected.gridImportToday',this.stateCache.get('meter.reverseActiveEnergy')?.value -
this.stateCache.get('collected.gridImportStart')?.value, {type: 'number'});
// compute consumption today
this.stateCache.set('collected.consumptionSum',this.stateCache.get('collected.accumulatedEnergyYield')?.value +
this.stateCache.get('meter.reverseActiveEnergy')?.value -
this.stateCache.get('meter.positiveActiveEnergy')?.value);
this.stateCache.get('meter.positiveActiveEnergy')?.value, {type: 'number'});
this.stateCache.set('collected.consumptionToday', this.stateCache.get('collected.consumptionSum')?.value -
this.stateCache.get('collected.consumptionStart')?.value);
this.stateCache.get('collected.consumptionStart')?.value, {type: 'number'});
//compute battery
this.stateCache.set('collected.totalCharge',totalCharge, {type: 'number'});
this.stateCache.set('collected.totalDischarge',totalDisCharge, {type: 'number'});
this.stateCache.set('collected.currentDayChargeCapacity',charge, {type: 'number'});
this.stateCache.set('collected.currentDayDischargeCapacity',disCharge, {type: 'number'});
this.stateCache.set('collected.ratedCapacity',ratedCap, {type: 'number'});
this.stateCache.set('collected.SOC',Math.round(load/ratedCap), {type: 'number'});
}


Expand All @@ -537,7 +571,7 @@ class Registers {


async _initState(path, state) {
await this.adapter.setObjectAsync(path+state.id, {
await this.adapter.setObjectNotExistsAsync(path+state.id, {
type: 'state',
common: {
name: state.name,
Expand Down Expand Up @@ -598,7 +632,7 @@ class Registers {
if (field.mapper) {
value = await field.mapper(value);
}
this.stateCache.set(path+state.id, value, field?.storeAlways);
this.stateCache.set(path+state.id, value, { stored : field?.storeAlways} );
}
}
}
Expand Down Expand Up @@ -683,22 +717,22 @@ class Registers {
this.storeStates(); //fire and forget
}

async loadStates() {
let value = await this.adapter.getStateAsync('collected.gridExportSum');
this.stateCache.set('collected.gridExportSum',value?.val);
value = await this.adapter.getStateAsync('collected.gridImportSum');
this.stateCache.set('collected.gridImportSum',value?.val);
async _loadStates() {
let value = await this.adapter.getStateAsync('collected.gridExportStart');
this.stateCache.set('collected.gridExportStart',value?.val, {type : 'number', stored : true });
value = await this.adapter.getStateAsync('collected.gridImportStart');
this.stateCache.set('collected.gridImportStart',value?.val, {type : 'number', stored : true });
value = await this.adapter.getStateAsync('collected.consumptionStart');
this.stateCache.set('collected.consumptionStart',value?.val);
this.stateCache.set('collected.consumptionStart',value?.val, {type : 'number', stored : true });
}

// one minute before midnight - perform housekeeping actions
async mitnightProcess () {
// copy current export/import kWh - used to compute daily import/export in kWh
this.stateCache.set('collected.gridExportSum',this.stateCache.get('meter.positiveActiveEnergy')?.value);
this.stateCache.set('collected.gridImportSum',this.stateCache.get('meter.reverseActiveEnergy')?.value);
this.stateCache.set('collected.gridExportStart',this.stateCache.get('meter.positiveActiveEnergy')?.value, {type : 'number'});
this.stateCache.set('collected.gridImportStart',this.stateCache.get('meter.reverseActiveEnergy')?.value, {type : 'number'});
// copy consumption Sum to Start for the next day
this.stateCache.set('collected.consumptionStart',this.stateCache.get('collected.consumptionSum')?.value);
this.stateCache.set('collected.consumptionStart',this.stateCache.get('collected.consumptionSum')?.value, {type : 'number'});
this.storeStates(); //fire and forget
}

Expand Down
3 changes: 0 additions & 3 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ const Registers = require(__dirname + '/lib/register.js');
const ModbusConnect = require(__dirname + '/lib/modbus_connect.js');
const {dataRefreshRate} = require(__dirname + '/lib/types.js');


// Load your modules here, e.g.:
// const fs = require("fs");

class Sun2000 extends utils.Adapter {

Expand Down Expand Up @@ -42,7 +40,6 @@ class Sun2000 extends utils.Adapter {
// this.on('objectChange', this.onObjectChange.bind(this));
// this.on('message', this.onMessage.bind(this));
this.on('unload', this.onUnload.bind(this));
//this.runWatchDog();
}

getInverterInfo(id) {
Expand Down
Loading