Batrium to Mobile (UDP, Arduino, Thingspeak)

Regalo

New member
Joined
May 8, 2019
Messages
17
All,

Up and running for 2 weeks. (Issues and all...) Being frustrated that WM had to be running to get data to thingspeak, or to mobile app, monitoring new baby while it's crying.

So, I connected an little Aduino (needed for more temp monitoring with DS18B20's. Still TODO.)
Receiving UDP from Batrium to Arduino and bumping it to thingspeak. Then easily available on mobile. Almost as cheap as chips, but cheaper than chips and bear.

Some links:
THis chap got me going in LinqPad to get UDP understanding.
https://forums.aeva.asn.au/viewtopic.php?f=64&t=5768
Daromer link to Batrium UDP packet file/spec (I think. Found it somewhere.)
https://github.com/Batrium/WatchMon.../WatchMon Wifi UDP protocol sw1.0.30 v1.0.pdf

Many mobile apps available reading your thingspeak data.


POC working posting 2 fields to thingspeak. Very simple code to get it working. No local storage, just bumping data forward.

Adruino can be close to your pack, or anywhere on the network. Quite a lot of benefits and uses.
---------------------------------------------

Code:
#include <WiFi.h>
#include <WiFiUdp.h>
#include <ThingSpeak.h>

const char* ssid  = "YOUR SSID";
const char* password = "YOUR WIFI PWD";
const int udpPort = 18542; //Port for receiving Batrium messages

unsigned long myChannelNumber = 1234566;//Your thingspeak channel #
const char * myWriteAPIKey = "abdde....";//your thingspeak write api key

WiFiServer server(80); //For later. Cann then access on local wifi network via browser. WIP.
//create UDP instance
WiFiUDP udp;
WiFiClient client;


void setup()
{
  Serial.begin(115200);
  pinMode(2, OUTPUT);   // set the LED pin mode

  delay(10);

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
  server.begin();
  udp.begin(udpPort);
  ThingSpeak.begin(client); 
}

void loop(){

 Fetch();
 delay(60000);
}

 float cell_voltsMin;
 float cell_voltsMax;
 float cell_voltsAvg; //3
 uint8_t cell_bypass_cnt;//1
 float shunt_volts;//4
 float shunt_amps;//5
 float shunt_power;//6
 float shunt_soc; //8
 float shunt_cap_to_full;//7
 float shunt_cap_to_empty;//2

void Fetch()
{
 uint16_t tmp16;
 uint8_t tmp8;
 bool hasSoc=false;
 bool hasVolts=false; 
 //receive response from server, it will be HELLO WORLD
 while(hasSoc == false || hasVolts == false)
 {
  udp.parsePacket();
  uint8_t buffer[1024] = "";
  if(udp.read(buffer, 1024) > 0)
  {
   if(buffer[1]==51 && buffer[2] ==63 && hasSoc == false)
   {
    Serial.println("Reading 5163");
    
    memcpy(&shunt_cap_to_full, &buffer[34], sizeof(float));
    shunt_cap_to_full = shunt_cap_to_full / 1000;

    memcpy(&shunt_cap_to_empty, &buffer[38], sizeof(float));
    shunt_cap_to_empty = shunt_cap_to_empty / 1000;

   memcpy(&tmp8, &buffer[32], sizeof(uint8_t));
   
    shunt_soc = (float(tmp8) / 2)-5;
    Serial.println("shunt_soc x: " + String(tmp8) + " shunt_soc:" + String(shunt_soc));
    hasSoc = true;
   }
   else if(buffer[1]==50 && buffer[2] ==62 && hasVolts == false)
   {
    Serial.println("Reading 5062");

    memcpy(&cell_bypass_cnt, &buffer[33], sizeof(uint8_t));

    memcpy(&tmp16, &buffer[8], sizeof(uint16_t));
    cell_voltsMin = float(tmp16) / 100;

    memcpy(&tmp16, &buffer[10], sizeof(uint16_t));
    cell_voltsMax = float(tmp16) / 100;
    
    memcpy(&tmp16, &buffer[28], sizeof(uint16_t));
    cell_voltsAvg = float(tmp16) / 1000;
    
    memcpy(&tmp16, &buffer[40], sizeof(uint16_t));
    shunt_volts = float(tmp16) / 100;

    memcpy(&shunt_amps, &buffer[42], sizeof(float));
    shunt_amps = shunt_amps / 1000;
 
    memcpy(&shunt_power, &buffer[46], sizeof(float));
    shunt_power = shunt_power ;
    hasVolts = true;
   }
  }
 }

 SendToSpeak();
}

void SendToSpeak()
{

 /* float cell_voltsAvg; //3
 uint8_t cell_bypass_cnt;//1
 float shunt_volts;//4
 float shunt_amps;//5
 float shunt_power;//6
 float shunt_soc; //8
 float shunt_cap_to_full;//7
 float shunt_cap_to_empty;//2
 */
  // set the fields with the values
  ThingSpeak.setField(1, cell_bypass_cnt);
    ThingSpeak.setField(2, shunt_cap_to_empty);
    ThingSpeak.setField(3, cell_voltsAvg);
    ThingSpeak.setField(4, shunt_volts);
    ThingSpeak.setField(5, shunt_amps);
    ThingSpeak.setField(6, shunt_power);
    ThingSpeak.setField(7, shunt_cap_to_full);
    ThingSpeak.setField(8, shunt_soc);
   
    // set the status
   // ThingSpeak.setStatus("CZ Updating status");
      // write to the ThingSpeak channel
    int x = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
    if(x == 200){
     Serial.println("Channel update successful.");
    }
    else{
     Serial.println("Problem updating channel. HTTP error code " + String(x));
    }
}
 
I'm interested in this as I currently parse the Batrium output files - but it only lets me get info every 5 minutes. The option for 30sec and 1min etc do not work. I can read/write code OK and I understand packets, bytes, bits etc.

But I'm stuck on visualizing the basic method of retrieving UDP packets form the Batrium - is it a URL to query some kind of wifi device? or one of these USB -> XXX devices?

If its wifi, how do you work around when the Batrium WiFi cuts out now and then? (and I have to do a hard reboot of the device to restore the wifi)
 
OffGridInTheCity:
Cuts out what? I dont think i have rebooted my batriums for over 6 months and i get data every like 300ms from them via WatchmonUdpListener i built and that is running on raspberry Pi. Yes its Wifi since UDP is network and batrium only do wlan.
If you look at my code above you get all code needed for fetching the data and it doesnt take much to convert it to c++/arduino code.

I have also done a couple of ESP8266 modules fetching batrium data both to influx and mqtt and also directly to smaller screens. Though havent published any code for it.
 
Korishan, tx. Did not know about the code block.

OffGridInTheCity,
According to the spec of the Batrium UDP, certain packets has quite a high rate of update. Way less than a min, so that should not be a problem. The file method, although not much investigate, seemed not the right way for real time.

As for the Batrium loosing WIfi connection, can't help there either. Note on code above, if it looses Wifi, you will need to reboot. It is only proof of concept, and needs updating/fixing, but enough to get started.

My understanding of UDP: No, it's not a url. It's like TCP, but the server, seems to me, broadcasts to anyone listening on the port on your Wifi Network. (Still learning the UDP protocol.) Port # in the code, and Batrium UDP spec. Port 18542.

So, to get it going, the quickest steps are as follows.
1. Follow the Batrium documentation how to set up communication and posting to thingspeak.com. Their manual is OK.
https://www.batrium.com/pages/watchmon-toolkit-howto-thingspeak
2. Install any Playstore app reading from your thingspeak account. (or Apple.) There are quite a few.
3. Once all is working, you need your WM software to be running in order to post the data to thingspeak.

Test above and if happy, then continue:

4. Get a cheap ESP32 arduino. (Or bluetooth ESP8266, R-PI, or any other.)
5. Install WIFI, UDP and ThingSpeak libraries.
6. Run code above, changing the parameters to post to your channel fields on thingspeak, in your arduino app.

It is simpler than you think. But do 1st 3 steps, to get the 1st half working, then the Arduino bit.

Hope this helps.
 
If you go Rasp or equal just install WatchmonUDPlistener and you dont have to work so much. You also get the protocol updated from Batrium directly ;)
 
@Regalo - thank your for your comment but the thingspeak is a different solution than reading UDP packets I believe. I actually did a quick thingspeak setup and it worked (and is pretty easy for quick web interface), but of course I don't want any of my info in the cloud and setting up a local thingspeak server, while doable, doesn't seem that interesting to me.

@Daromer - "....just install WatchmonUDPlistener ..." - OK I get that this is a way go access an endpoint to get UDP packets. I'll focus onthat, thanks.

All - as far as wifi dying... yea.. it just stops and I have to do a power reset (i.e. disconnect power and do cold restart). It seems to happen after a colder/damper evening and then a bright sunny morning as sun comes up (warms things up?) around 9am'ish. My Batrium is under the house where it's cooler and while its not near any vents, the vents are open to outside air. For example, it happened this morning. Under house temp was 61F and then sun came up 100% clear skies / bright and wifi stopped working. The computer is about 4 feet from the Batrium, so it shouldn't be an interference issue.

I did the Batrium update about a month ago so its pretty current - but its done this 20 times over the last 12 months. Its weird, I agree and I don't mean to pollute this thread with this issue :)

OK - I'm going to take the plunge. Just ordered a Pi4 Model B with WiFi . Wish me luck!
 
Regalo, what does the end output look like for you on thingspeak, etc?

Has anyone used the Watchmons's USB interface to pull data without the usual Windows Batrium s/w (thinking more reliable than the WiFi?)
Eg connected a Watchmon to a Raspberry Pi USB port?
 
OffGridInTheCity,
I think for a full solution is the PI and Daromer's implementation nice. Might end up there as well.
Just a note, I use UDP, but instead of saving it locally, just bumping it over to thingspeak.

Redpacket,
Thingspeak is normal graph, and below is what it looks like on mobile. Follow the Batrium installation to get it going.


image_cyctac.jpg


image_omqhjf.jpg
 
@Regalo Your code is great and I have tested it and everything works fine

I have one question to ask you in your code you used this
Code:
   if(buffer[1]==51 && buffer[2] ==63 && hasSoc == false){
    Serial.println("Reading 5163");

From where did you obtained the buffer numbers as I would like to add a relay when the Watchmon 5 gets a Critical Fault.


image_knktxh.jpg
 
Back
Top