Giter Site home page Giter Site logo

neilsheps / renogy-bt2-reader Goto Github PK

View Code? Open in Web Editor NEW
15.0 2.0 2.0 107 KB

Arduino library to interrogate Renogy devices using BT2 dongle over bluetooth

License: GNU General Public License v3.0

C++ 98.04% C 1.96%
arduino ble bluetooth bluetooth-low-energy dcdc-converter mppt mppt-charger renogy renogy-bt solar

renogy-bt2-reader's Introduction

Renogy-BT2-Reader

Arduino library to interrogate Renogy devices that use a BT2 dongle over bluetooth

Renogy make a number of solar MPPT controllers, DC:DC converters and other devices. Their more recent products use a bluetooth dongle known as a BT2, but Renogy has never released any documentation on how to interrogate these devices. By using Wireshark on an Android Phone and Renogy's BT app, I was able to decrypt the protocol used. I built an Arduino library compatible with Adafruit's nrf52 series devices. This library has been tested successfully with a Renogy DCC30S device, and may work with other Renogy devices if the registers are known and decribed in the library header file.

This library is strictly use at your own risk. I am not releasing any code on how to write to registers. Use the Renogy apps (and any validation they provide) for that please.

The BT2 Protocol

First, a BLE Central device scans for service 0xFFD0 and a manufacturer ID 0x7DE0 and attempts a connection. There are two services and two characteristics that need to be set up

txService        0000ffd0-0000-1000-8000-00805f9b34fb     // Tx service
txCharacteristic 0000ffd1-0000-1000-8000-00805f9b34fb     // Tx characteristic. Sends data to the BT2

rxService        0000fff0-0000-1000-8000-00805f9b34fb     // Rx service
rxCharacteristic 0000fff1-0000-1000-8000-00805f9b34fb     // Rx characteristic. Receives notifications from the BT2

The data format is relatively simple once you read enough data. All 2 byte numbers are big endian (MSB, then LSB). A full list of registers and their functions is available here. An example data handshake looks like this:

ff 03 01 00  00 07 10 2a                                     Command sent to BT2 on characteristic FFD1
[]                                                           All commands seem to start with 0xFF
   []                                                        0x03 appears to be the command for "read"
      [___]                                                  Starting register to read (0x0100)
             [___]                                           How many registers to read (7)
                   [___]                                     Modbus 16 checksum, MSB first on bytes 0 - 5 inclusive

ff 03 0e 00 64 00 85 00 00 10 10 00 7a 00 00 00 00 31 68     Data response from BT2 through notification on characteristic FFF1
[]                                                           Replies also start with 0xFF
   []                                                        Acknowledges "read", I believe
      []                                                     Length of data response in bytes (usually 2x registers requested, so 14 here)
         [___]                                               Contents of register 0x0100 (Aux batt SOC, which is 100%)
               [___]                                         Contents of register 0x0101 (Aux batt voltage * 10, so 13.3v)
                     [___] [___] [___] [___] [___]           Contents of registers 0x0102 through 0x0106
                                                   [___]     Modbus 16 checksum on bytes 0 - 16 inclusive (in this case)


6d 61 69 6e 20 72 65 63 76 20 64 61 74 61 5b 66 66 5d 20 5b  20 byte ACK sent to BT2 on characteristic FFD1
 m  a  i  n     r  e  c  v     d  a  t  a  [  f  f  ]     [  it reads "main recv data[ff] [" and the ff corresponds to the first byte
                                                             of every 20 byte notification received; so a 50 byte datagram (3 notifications)
                                                             might trigger an ack sequence like "main recv data[ff] [", "main recv data[77] [",
                                                             and "main recv data[1e] [" depending on data received.  
                                                             The BT2 seems to respond OK without this ACK, but I do it also, as that's what the
                                                             Renogy BT app does

Using the BT2Reader library

Setup is fairly straightforward. You need to set up the Bluefruit.Scanner preparatory calls as usual - see Adafruit's examples for help here. The setup functions are:

uint16_t myConnectionHandle = BLE_CONN_HANDLE_INVALID;       // a variable to retain connection handle number
BT2Reader bt2Reader;                                         // creating the class that handles interacting with the BT2

In begin() {} before starting to scan, you need to add these lines:

Bluefruit.begin(0, 2);                                       // sets bluefruit to 2 central connections here
bt2Reader.setDeviceTableSize(1);                             // creates space for 1 connection to a BT2 device (the library can handle more)
bt2Reader.addTargetBT2Device((char *)"BT-TH-XXXXXXX");       // sets the target BT2 device name to connect to
						             // you can also omit this and it will connect to whichever BT2 device it can find
							     // you can also addTargetBT2Device(uint8_t * macAddress) where macAddress is 6 bytes
bt2Reader.setLoggingLevel(BT2READER_VERBOSE);		     // BT2READER_ERRORS_ONLY and BT2READER_QUIET also supported
bt2Reader.begin();                                           // initializes the class

Add these lines to scanCallback:

void scanCallback(ble_gap_evt_adv_report_t* report) {
	if (bt2Reader.scanCallback(report)) {                // returns true if scanCallback found a BT2 device, so you can skip other checks
                                                             // and save a few CPU cycles
		Bluefruit.Scanner.resume();
		return;
	}
	/* Your code to check for other devices while scanning*/
	Bluefruit.Scanner.resume();
}

Add these lines to connectCallback:

void connectCallback(uint16_t connectionHandle) {
	if (bt2Reader.connectCallback(connectionHandle)) {   // checks if device is a BT2, returns true on successful BT2 connection, false otherwise
		myConnectionHandle = connectionHandle;       // store the connection handle on a successful connection
		return;
	}
	// any other connection code goes here

}

Add these lines to disconnectCallback

void disconnectCallback(uint16_t connectionHandle, uint8_t reason) {
	if (bt2Reader.disconnectCallback(connectionHandle, reason)) {	// returns true if it's a BT2 device that's being disconnected
		myConnectionHandle = BLE_CONN_HANDLE_INVALID;
		return;
	}
	// other disconnection callback code here
}

At any time in the main loop you can initiate a request for fresh data and reading it using this code:

uint32_t sendReadCommandTime = millis();
bt2Reader.sendReadCommand(myConnectionHandle, startRegister, numberOfRegisters);

/* usually it takes ~70-120ms to get a response back from the BT2 depending on how many registers are requested */
while (!bt2Reader.getIsNewDataAvailable(myConnectionHandle) && (millis() - sendReadCommandTime < 5000)) {
	delay(2);
}

/* you can obtain the register values (16 bits) by calling getRegister */
for (int i = 0; i < numberOfRegisters; i++) {
	Serial.printf("Register 0x%04X contains %d\n", 
		startRegister + i,
		bt2Reader.getRegister(myConnectionHandle, startRegister + i)->value
	);
}

/* you can also print out each register formatted how it's intended with printRegister.
   it can handle float, decimal, char arrays and even bit flags */
for (int i = 0; i < numberOfRegisters; i++) {
	bt2Reader.printRegister(myConnectionHandle, startRegister + i);
}

renogy-bt2-reader's People

Contributors

neilsheps avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

renogy-bt2-reader's Issues

How to compile

I'm very interested in this as an Arduino alternative to Renogy-BT1 but it's not really clear how to use the library. main.cpp seems to contain the extra details from the readme but the link to the Adafruit library is to an ino which doesn't have all the sections that you talk about.

I'd be grateful for any further help you can give.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.