0.7.3 • Published 3 months ago

growatt v0.7.3

Weekly downloads
-
License
MIT
Repository
github
Last release
3 months ago

Logo

NPM version Downloads week Downloads month Downloads year

NPM

Logorowatt API for Inverter

this is an Node for the API on the Growatt© Shine Webserver. (Shine provided by Growatt©. I'm not affiliated.)

This implementation is based on the refectured eebinterface from Growatt© Shine.

Install

npm install growatt

Debug

This API supported debugging. you have to set the environment variable DEBUG

set DEBUG=growatt:*
set DEBUG=growatt:api
set DEBUG=growatt:verbose
set DEBUG=growatt:queue

Promise

This NODE-Implementation works with promise.

Understanding javascript promises

Modern Asynchronous JavaScript with Async and Await

Simple Impemation

"use strict"
const api = require('growatt')

const user="xxx"
const passwort="xx"
const options={}

async function test() {
  const growatt = new api({})
  let login = await growatt.login(user,passwort).catch(e => {console.log(e)})
  console.log('login:',login)
  let getAllPlantData = await growatt.getAllPlantData(options).catch(e => {console.log(e)})
  console.log('getAllPlatData:',JSON.stringify(getAllPlantData,null,' '));
  let logout = await growatt.logout().catch(e => {console.log(e)})
  console.log('logout:',logout)
}

test()

Constructor

Please note that you have to create an instance since version 0.2.0.

ParameterTypeDefaultDescription
configObjectSee belowControls the processing

The constructor has a config object as parameter. This is optional.

Config

configTypeDefaultDescription
serverString'https://server.growatt.com'The Growatt server
indexCandIBooleanfalseSet to true if your Growatt page Plant is a C&I Plant page with indexbC or plantDo in the Path from the Growatt webinterface.
timeoutInteger5000Session timeout in ms.
headersObject{}custom header like {'X-Custom-Header': 'foobar'}.
lifeSignCallbackfunctionundefinedCalled before each Axios call.
const api = require('growatt')
const growatt = new api()

Login

There are several options for logging in:

Login with user and password

ParameterTypeDefaultDescription
userString-The username
passordString-The password
  let login = await growatt.login(user,passwort).catch(e => {console.log(e)})

With resolve, the response from the website is returned. Usually the object: { result: 1, msg: 'OK' }

With reject an exception is thrown which contains the error object with result less then 1.

Login with key

ParameterTypeDefaultDescription
keyString-The key

You can get the key by having an email sent to you on the Grwatt website for a third party to display the data. The key is the combination of numbers and letters in the link. It has 96 characters.

  let login = await Growatt.sharePlantLogin(key).catch(e => {console.log(e)})

With resolve, the response from the website is returned. Usually the object: { result: 1, msg: 'OK' }

With reject an exception is thrown which contains the error object with result less then 1.

Login to Demo

ParameterTypeDefaultDescription

This plugin is intended for testing. On the Growatt page you can view the data from many systems. The problem is that the ID of the system is different here every time you login.

I needed it so that I could see how the messages to the different inverters are structured.

  let login = await Growatt.demoLogin().catch(e => {console.log(e)})

Get all plant data

ParameterTypeDefaultDescription
optionObjectSee belowControls the processing

This function knows the individual types of the inverter and calls up the data.

This function can be controlled via an option so that you don't always have to call up all the data that is possible:

Option

OptionTypeDefaultDescription
plantDataBooleantrueTrue calls the description dataset of the plant.
deviceDataBooleantrueTrue calls the description dataset of the plantdevice.
weatherBooleantrueTrue calls the weather dataset of the plant.
faultlogBooleanfalseTrue retrieves the plant's fault logs. An array with the most recent event first is returned.
faultlogdateString'YYYY'It is only taken into account if faultlog is true. It must be a string with the date in 'YYYY', 'YYYY-MM', 'YYYY-MM-DD'.
faultlogdateindexBooleantrueIt is only taken into account if faultlog is true. The array is converted into timestampsobjects.
plantIdIntegerundefinedThe ID of a plant. So that the output can be restricted. Attention, the ID is constantly changing on demologin.
totalDataBooleantrueRetrieves the data integrals. The sums since start time.
statusDataBooleantrueThis is not available for all systems. Here, the current operating status, fuel injection, battery charge and generation is called up. However, the data is also contained in historyLast.
deviceTypBooleanfalseAdd the device type to the Output.
historyLastBooleantrueThe last data record from the system history table is called up here.
historyAllBooleanfalseAll data records from the system history table is called up here.
historyLastStartDatenew Date()yesterdayThe start time for retrieving the history.
historyLastEndDatenew Date()tomorrowThe end time for retrieving the history.
historyStartInteger0The server does not send all data for the time range. With the starting index you get the next rows.

The call

After waiting to log in with await. Can the data be retrieved using this method. In response, an object comes out that contains the data of the length.

  options = {plantData:false,deviceData:true,deviceTyp:true,weather:false,chartLastArray:true}
  let getAllPlantData = await growatt.getAllPlantData(options).catch(e => {console.log(e)})
  console.log('getAllPlatData:',JSON.stringify(getAllPlantData,null,' '));

Logout

After retrieving the data, you should log out of the page again. It is the same call for all three login variants.

  let logout = await growatt.logout().catch(e => {console.log(e)})

isConnected

It is also possible to have the connection open and to check whether the API is still connected.

  if (growatt.isConnected()) {
  }

getDataLoggers

Returns a list of data loggers with information

  let loggers = await growatt.getDataLoggers().catch(e => {console.log(e)})

getDataLoggerRegister

ParameterTypeDefaultDescription
dataLogSnString-The serial number
addrInteger-The register

Returns the value of a datalogger register

  //api.LOGGERREGISTER.INTERVAL
  //api.LOGGERREGISTER.SERVERIP
  //api.LOGGERREGISTER.SERVERPORT
  let register = await growatt.getDataLoggerRegister(loggers[0].sn, api.LOGGERREGISTER.INTERVAL).catch(e => {console.log(e)})

The answer is an object

ParameterTypeDescription
msgStringThe value
successStringOk or bad

setDataLoggerRegister

Warning an incorrect register with the wrong value can destroy or damage the logger. Writing to the Datenlohgger is at your own risk.

ParameterTypeDefaultDescription
dataLogSnString-The serial number
addrInteger-The register
valueString-The value to set

Sets the value of a datalogger register

  //api.LOGGERREGISTER.INTERVAL
  //api.LOGGERREGISTER.SERVERIP
  //api.LOGGERREGISTER.SERVERPORT
  let res = await growatt.setDataLoggerRegister(loggers[0].sn, api.LOGGERREGISTER.INTERVAL, 1).catch(e => {console.log(e)})

The answer is an object

ParameterTypeDescription
msgStringAn information
successStringOk or bad

setDataLoggerParam

Warning an incorrect register with the wrong value can destroy or damage the logger. Writing to the Datenlohgger is at your own risk.

ParameterTypeDefaultDescription
dataLogSnString-The serial number
paramTypeInteger-The function number
valueString-The value to set

Sets the value of the datalogger

  //api.LOGGERFUNCTION.INTSERVERIP
  //api.LOGGERFUNCTION.SERVERNAME
  //api.LOGGERFUNCTION.SERVERPORT
  let res = await growatt.setDataLoggerRegister(loggers[0].sn, api.LOGGERFUNCTION.SERVERPORT, 5279).catch(e => {console.log(e)})

The answer is an object

ParameterTypeDescription
msgStringAn information
successStringOk or bad

setDataLoggerRestart

ParameterTypeDefaultDescription
dataLogSnString-The serial number

Sets the value of the datalogger

  //api.LOGGERFUNCTION.INTSERVERIP
  //api.LOGGERFUNCTION.SERVERNAME
  //api.LOGGERFUNCTION.SERVERPORT
  let res = await growatt.setDataLoggerRestart(loggers[0].sn).catch(e => {console.log(e)})

The answer is an object

ParameterTypeDescription
msgStringAn information
successStringOk or bad

checkDataLoggerFirmware

ParameterTypeDefaultDescription
typeInteger-The logger type number
versionString-The logger firmware version

It is checked whether an update is available

  let res = await growatt.checkDataLoggerFirmware(loggers[0].deviceTypeIndicate,loggers[0].firmwareVersion).catch(e => {console.log(e)})

The answer is an object

ParameterTypeDescription
msgStringAn information
successStringOk or bad

getInverterCommunication

Warning: An incorrect value can lead to the destruction of the inverter. The writing to the inverter is at your own risk.

ParameterTypeDefaultDescription
typeString-The Invertr type from the SN object

This function does not require a connection to the server. The answer is an object

ParameterTypeDescription
Object confThe configuration

Object conf

ParameterTypeDescription
nameStringThe term for it
paramObject paramThe list of the Params
subReadString arrayIf specified, further objects must be loaded in order to receive the object completely
isSubreadStringIt is listed as subRead in another config. The param is empty, it is defined for subRead objects.

Attention different inverters have different parameters. Therefore, the parameters cannot be crossed under the types Object param

ParameterTypeOptionalDescription
nameStringnoThe term for it
typeStringnoThe valuetype
defanyon not readIf the parameter is not readable, it contains a value for the default value
unitStringif knownThe unit of value
valuesObjectif neededContains list of translation of values ​​as Object. Key : String. The key is the value that must be passed. The string is an English description for the value.

The Value Types from the Parameter

valuetypeTypeDescription
INUM_0_100Integervalue 0 ... 100
INUM_0_1Integervalue 0 ... 1
BOOLBooleantrue/false
STIME_H_MINString for Timeformat 'HH:MI'
DATETIMEIntegerDate.timeOf()
  let a = allPlantData[Object.keys(allPlantData)[0]].devices;
  let sn = Object.keys(a)[0];
  let type = a[sn].growattType;
  let com = Growatt.getInverterCommunication (type);

getInverterSetting

Warning: An incorrect value can lead to the destruction of the inverter. The writing to the inverter is at your own risk.

ParameterTypeDefaultDescription
typeInteger-The logger type number
funcString-The to read
serialNumString-Inverters Serial number

Returns a list of the Values as defined

The answer is an object

ParameterTypeDescription
msgStringAn information
successStringOk or bad
param<..>eachFrom the Param List

With some inverters, it is not always possible to read the data due to the connection via RS232. If a process is in progress, the second query is rejected. Therefore, the requests are placed in a queue and processed sequentially. If the inverter does not send any data but reports success, the request is repeated.

  // Growatt must be connected

  const allPlantData = await Growatt.getAllPlantData(options).catch(e => {console.log(e);});
  console.log('Fatched all Data');
  if (allPlantData) {
    let a = allPlantData[Object.keys(allPlantData)[0]].devices;
    let sn = Object.keys(a)[0];
    let type = a[sn].growattType;
    let com = Growatt.getInverterCommunication (type);
    console.log(com);
    let run = []
    Object.keys(com).forEach(name => {
        if (com[name].subRead) {
          com[name].subRead.forEach(name => {
                                            run.push(Growatt.getInverterSetting(type, name, sn)
              .then(r => {
                console.log(name,r);
              })
              .catch(e => {
                console.log(name,e);
          }))})
        }
        if (!com[name].isSubread) {
          run.push(Growatt.getInverterSetting(type, name, sn)
          .then(r => {
            console.log(name,r);
          })
          .catch(e => {
            console.log(name,e);
          }))
        }
    })
    await Promise.all(run)
  }

setInverterSetting

Warning: An incorrect value can lead to the destruction of the inverter. The writing to the inverter is at your own risk.

ParameterTypeDefaultDescription
typeInteger-The logger type number
funcString-The to read
serialNumString-Inverters Serial number
valObject-values to set

The val object

ParameterTypeDescription
param<..>eachFrom the Param List

With some inverters, it is not always possible to read the data due to the connection via RS232. If a process is in progress, the second query is rejected. Therefore, the requests are placed in a queue and processed sequentially. If the inverter does not send any data but reports success, the request is repeated.

    let a = allPlantData[Object.keys(allPlantData)[0]].devices;
    let sn = Object.keys(a)[0];
    let type = a[sn].growattType;
    let v = {param1: (new Date()).getTime()}
    await Growatt.setInverterSetting(typ, 'time', sn, v);

getNewPlantFaultLog

ParameterTypeDefaultDescription
plantIdInteger-The plantId
dateString'YYYY'It must be a string with the date in 'YYYY', 'YYYY-MM', 'YYYY-MM-DD'
deviceSnString''Inverters Serial number, can be an empty string to request all
toPageNumInteger1Go to a specific page

It queries the fault log and returns the posts.

The answer is an object

ParameterTypeDescription
resultInteger1 => Ok
objObjectResponse object

Response object

ParameterTypeDescription
pagesIntegerNumber of possible pesponse pages
currPageIntegerNumber of current pesponse page
datasArray of objectMessage objects
countIntegerMessages in the array

Response datas object as array

ParameterTypeDescription
deviceTypeStringDescription of which device type
eventIdStringCode for the event
batSnStringSerial number of the battery if the event came from it
solutionStringA suggestion from Growatt
eventSolutionStringAnother suggestion from Growatt
aliasStringThe device's alias
eventNameStringThe name or description of the event
snStringThe serial number of the equipment
timeString (date)When it happened YYYY-MM-DD HH:MI:SS
deviceSnStringThe serial number of the device

Speedup data interval new method

  • Open the ShinePhone app
  • Click on attachment below
  • Top right +, then list data loggers
  • Click on existing data logger
  • Configure data logger
  • Wireless hotspot mode
  • Put the stick in AP mode
  • Connect to Wifi hotspot, PW 123456789 ? <- check again
  • Continue
  • Advanced
  • Time setting
  • Interval to 1
  • Enter password growattYYYYMMDD (e.g.growatt20220209)
  • Unlock
  • Click and apply changes
  • Exit hotspot mode

There is no change to the charts on growatt side. There you can only see a change in the data from the datalogger.


License (MIT)

Copyright (c) 2020 Chris Traeger

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

0.7.3

3 months ago

0.7.2

3 months ago

0.7.1

8 months ago

0.7.0

8 months ago

0.5.4

10 months ago

0.5.3

11 months ago

0.5.6

10 months ago

0.5.5

10 months ago

0.5.0

11 months ago

0.5.2

11 months ago

0.6.0

9 months ago

0.5.1

11 months ago

0.4.1

1 year ago

0.4.0

1 year ago

0.3.0

2 years ago

0.2.14

2 years ago

0.2.13

2 years ago

0.2.12

2 years ago

0.2.11

2 years ago

0.2.10

2 years ago

0.2.6

2 years ago

0.2.9

2 years ago

0.2.8

2 years ago

0.2.5

2 years ago

0.2.4

2 years ago

0.2.3

2 years ago

0.2.2

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago

0.0.9

3 years ago

0.0.8

3 years ago

0.0.7

3 years ago

0.0.6

3 years ago

0.0.5

3 years ago

0.0.4

3 years ago

0.0.3

3 years ago

0.0.2

4 years ago

0.0.1

4 years ago