Go Down

Topic: ESP8266 float to java float via WebSocket (Read 94 times) previous topic - next topic

warwound

I have an ESP8266 with a BMP280 sensor attached.
The ESP8266 connects to a java WebSocket server running on my local network and i want to send both pressure and temperature readings from the ESP8266 to the server - where i'll insert them into a database.

I have been unable to reconstruct the ESP8266 float in java and am hoping someone can help me.
I've reduced my sketch to a minimum, the important parts are:

A custom struct and union:

Code: [Select]

struct FloatPacket{
  uint8_t id;
  float value;
};

union UnionFloatPacket {
  FloatPacket packet;
  uint8_t bytes[5];
};


Two instances of the union:

Code: [Select]

#define PACKET_ID_PRESSURE 1
#define PACKET_ID_TEMPERATURE 2

UnionFloatPacket currentPressure;
UnionFloatPacket currentTemperature;

currentPressure.packet.id=PACKET_ID_PRESSURE;
currentTemperature.packet.id=PACKET_ID_TEMPERATURE;


Then sending of some test values from ESP8266 to java:

Code: [Select]

currentPressure.packet.value = 12.34F;
Serial.print("Pressure: ");
Serial.print(currentPressure.packet.value, 2);
Serial.print(" Pa");

Serial.print('\t');

currentTemperature.packet.value = 45.68F;
Serial.print("Temperature: ");
Serial.print(currentTemperature.packet.value, 2);
Serial.print(" C");

Serial.println();

webSocketClient.sendBIN(currentTemperature.bytes, 5);
webSocketClient.sendBIN(currentPressure.bytes, 5);


My serial console shows the expected output:

Quote
Pressure: 12.34 Pa   Temperature: 45.68 C
Next in my java websocket server:

Code: [Select]

private String getString(Object... parts) {
StringBuilder stringBuilder = new StringBuilder();
for (Object part : parts) {
stringBuilder.append(part.toString());
}
return stringBuilder.toString();
}

@OnMessage
public void handleMessage(ByteBuffer byteBuffer, Session session) {
// handle binary frame
if(byteBuffer.limit()==5){

byte packetId=byteBuffer.get();

// float debug = java.nio.ByteBuffer.wrap(messageBytes, 1, 4).order(java.nio.ByteOrder.nativeOrder()).getFloat();

int floatAsInt=0;
for(int i=4; i>0; i--){
floatAsInt = (floatAsInt << 8) + (byteBuffer.get(i) & 0xff);
}
float floatValue=Float.intBitsToFloat(floatAsInt);

Logger.getLogger(Server.class.getName()).log(Level.INFO, getString("bytes received: ", byteBuffer.get(0), ' ', byteBuffer.get(1), ' ', byteBuffer.get(2), ' ', byteBuffer.get(3), ' ', byteBuffer.get(4)));

switch(packetId){
case PACKET_ID_PRESSURE:
Logger.getLogger(Server.class.getName()).log(Level.INFO, getString("pressure: ", floatValue));
break;

case PACKET_ID_TEMPERATURE:
Logger.getLogger(Server.class.getName()).log(Level.INFO, getString("temperature: ", floatValue));
break;

default:
Logger.getLogger(Server.class.getName()).log(Level.INFO, getString("Unrecognised packet id: ", packetId));
}

// int pressureAsInt = (messageBytes[3] << 24) | ((messageBytes[2] & 0xff) << 16) | ((messageBytes[1] & 0xff) << 8) | (messageBytes[0] & 0xff);
// float pressure = Float.intBitsToFloat(pressureAsInt);
// int temperatureAsInt = (messageBytes[7] << 24) | ((messageBytes[6] & 0xff) << 16) | ((messageBytes[5] & 0xff) << 8) | (messageBytes[4] & 0xff);
// float temperature = Float.intBitsToFloat(temperatureAsInt);
//
// StringBuilder log=new StringBuilder("Pressure: ");
// log.append(pressure);
// log.append(", temperature: ");
// log.append(temperature);
//
// Logger.getLogger(Server.class.getName()).log(Level.INFO, log.toString());

} else {
Logger.getLogger(Server.class.getName()).log(Level.INFO, getString("messageBytes has incorrect number of bytes: ", byteBuffer.limit()));
}
}


You can see the commented out code shows various other ways that i have tried to reconstruct my ESP8266 float in java - these methods did not work either.
The server logs currently shows:

Quote
pressure: -2.7755576E-17
bytes received: 1 0 0 0 -92
temperature: 1.37438953E11
bytes received: 2 0 0 0 82
So the ESP is sending these byte values: 0, 0, 0, -92 for float value 12.34
And byte values 0, 0, 0, 82 for float value 45.68

Where am i going wrong?
Thanks.


wildbill

#1
Mar 18, 2018, 11:31 am Last Edit: Mar 18, 2018, 11:38 am by wildbill
I can't read your Java code so I can only guess, but you may have endian issues q.v. Try declaring a float in Java and assign 12.34 to it and then dump the bytes that make it up out to see how they compare.

Edit: Another possibility is that you're calling getFloat on the bytes that make up a float and it's expecting a string such as "12.34" instead.

warwound

Thanks for the reply.

I have it fixed now.
The problem was using the struct within the union i think.
A google search led me to https://github.com/esp8266/Arduino/issues/1825

Where i read:

Quote
On many architectures, accessing word-sized values is only allowed when these values are aligned to word boundaries. This alignment is automatically done for structure members by the compiler.
So the bytes i was sending to the websocket server were not the bytes i wanted to send.
The compiler performed some optimisation, aligning the struct bytes on word boundaries effectively destroying my method of accessing them.

What an obscure fix for a simple problem!

PaulRB

I think you might as well send a float as ASCII text. Float is 4 bytes. Temp like "12.34" is 5 bytes, 6 if you need to add a "-". So it's not much more to transmit.

warwound

That is an easy fix and i had already got the values to successfully send using text.
I just wanted to learn why sending as bytes was not working - to satisfy my curiousity and for future reference.

I can now choose whether to use binary or text as i further develop my sketch.

Go Up