Official Losant + Particle Setup Tutorial


#1

Losant has released their Official Particle Setup Tutorial to show you how to quickly get your project setup to send data to Losant for storage and graphing.

Losant has a power backend programming interface to do all kinds of stuff with your data as it comes in.

Their dashboards are more customizable than anything else I have seen offered in this space.

The free account provides a generous 1 million incoming Particle Publishes for up to 10 unique devices which is way more than the other free tiers others provide. I can publish 200 bytes every 15 seconds and still not come close to hitting the free monthly data limits which is nice.

Their simple Particle Publish Integration allows a very easy way to send numbers, floats, and text data by simply separating each variable by the : sign. Then you can break each variable down on the backend of Losant as described in the toutorial. This method is much easier than the JSON formatting that is required for sending data to other platforms I have used.

Give it a shot, you’ll like it :spark:


Particle to Azure integration sending null values
Using WebHooks to Link to Web Services, I thought I had this figured out
Door open counter and time of days open
#2

Thanks for sharing!


#3

@GasGen This may be a better place to continue this discussion.

Here is how I have my setup working.

First the Particle Integration:

Next is the individual device setup page:


And then the workflow settings that separates the incoming webhook data into individual variables that match the variable names you entered on the device setup page where you named each variable and it’s data type either a number, boolean or string.

I have this setup so the variables are separated by a semi-colon : which makes it really easy to separate variables in the Particle Publish event you send out that Losant receives and then breaks down in the function shown below:

Next is the device state node that saves the new incoming data as a new variable:

Once this is setup correctly you should be able to see the incoming data in the Device Log window at the right of the screen where it says received payload.

The webhook my device sends out is just variables with a semi-colon separating each of them.

Let me know if this helps at all.


#4

Thank you so much for all your time Ryan.

So is your webhook name state? or is it newState?

Here is how my data is sent from Particle.

EF is my webhook event name… cf is the json form field in the webhook, and F is the data sent.

Particle.publish("EF", 
                "{\"cf\":\"" + F + 
                "\"}", 60, PRIVATE, NO_ACK); // NOTE Added NO-ACK to save data. 

I have deleted everything in Losant and am going to start from scratch trying some of your examples. I know I have the function payload data not entered correctly after reviewing yours. Along with not entering the device attributes correctly.


#5

The webhook name is: state

Here is what the Particle Publish code looks like.

  snprintf(publishStateString, sizeof(publishStateString), "%.2f:%.2f:%.2f:%u:%.2f:%.2f:%u:%u:%.2f:%u:%.2f:%.2f:%.2f:%.2f:%u:%u:%.2f:%.2f:%.2f:%.2f:%.2f:%.2f:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:",bms.GetVoltage(),bms.GetCurrent(),bms.GetCurrent() * bms.GetVoltage(),bms.RelativeSOC(),(bms.AverageTimeTillEmpty()/60),(bms.RemainingBatteryCapacity() - bms.FullBatteryCapacity()) / (bms.GetCurrent() *1000),bms.RemainingBatteryCapacity(),bms.FullBatteryCapacity(),(bms.GetTemp()* 9 / 5 + 32),bms.CycleCount(),bms.CellVoltage1(),bms.CellVoltage2(),bms.CellVoltage3(),bms.CellVoltage4(),bms.StateOfHealth(),bms.MaxError(),mppt.GetSolarInputVoltage(),mppt.GetSolarInputCurrent(),mppt.GetLTC4015BatVReading(),mppt.GetLTC4015BatIReading(),mppt.GetLTC4015BatIReading() * mppt.GetLTC4015BatVReading(),(((mppt.GetLTC4015DieTemp() -12010)/45.6) *9.0 / 5.0 + 32.0),0,0,0,0,0,0,0,0,ChgFet,DsgFet,ShutdownLoVoltage,DischargingDisabled,ChargingDisabled,SleepMode,CellBalancing,0,ChargeInhibit,ChargeSuspend,ChargeTermination,0,0,0,0,0,CellUnderVoltage,CellOverVoltage,0,0,0,OverloadDuringDischargeLatch,0,ShortCircuitDuringDischargeLatch,OvertemperatureDuringCharge,OvertemperatureDuringDischarge,UndertemperatureDuringCharge,UndertemperatureDuringDischarge,CxChargeTerm,NtcPause,ChargerSuspended,AbsorbCharge,ConstantVoltage,ConstantCurrent,LinLimitActive,VinUvClActiveMPPT,VinHiEnoughToCharge,VinOverVoltageLockout,ThermalShutdown,OKToCharge,ChargerEnabled );
      Particle.publish("State", publishStateString);

@ScruffR Taught me how to use the snprintf formatting to format the data that that the Publish event sends out as variable “publishStateString”.

This is really simple but may or maynot make sense at first glance.


#6

This post explains how to format webhook data using the snprintf function:


#7

WOW. not thats a long one. lol

Yea @ScruffR taught me how to map floating numbers… save me from pulling my hear out by simply adding a decimal.

This is how mine is written.

float flow = map(adc,2139.0, 10614.0, 0.0, 200.0);
String F = String::format("%.1f", flow);
if (Particle.connected() && millis()-lastpub > 60000) {
		lastpub = millis();

Particle.publish("EF", 
                "{\"cf\":\"" + F + 
                "\"}", 60, PRIVATE, NO_ACK); // NOTE Added NO-ACK to save data.

I just added the if particle.connected and No_auk this week after reading some of the other threads here. Saving me a TON of data. That and I had to shorten my webhook name, figured that helped as well.

So with this in mind for the varibles in Losant should I ignore the webhook name and concentrate on the data name “cf”?

Or would you suggest that I rewrite my particle.publish to match more of the setup you and scruff did?


#8

This is the original code that has the other variables commented out as I don’t need them published right now. Trying to maximize data.
This was how I had to write the string to get it into the webhook and over to google sheets.

Particle.publish("EF", 
                "{\"cf\":\"" + F + 
//               "\",\"v\":\"" + String::format("%.1f",fuel.getSoC()) + // BATTERY 
//                "\",\"c\":\"" + String::format("%.1f",fuel.getVCell()) + // CELL State 
//                "\",\"gp\":\"" + t.readLatLon() + // WORKED AND PUBLISHED  
                "\"}", 60, PRIVATE, NO_ACK); // NOTE Added NO-ACK to save data. 

#9

Try this.

#1 Create a Global Variable by placing this line of code above Setup().

This creates the bucket to hold the data we put into the publishStateString bucket. It’s large enough to hold all the data a Webhook can hold in a single Publish Event which is 255 bytes.

char publishStateString[256]; //This is used to hold the device status info we format and Particle Publish to Losant.

#2. Add this new publish code to your sketch.

snprintf(publishStateString, sizeof(publishStateString), "%.2f:",F );
Particle.publish("EF", publishStateString, 60, PRIVATE, NO_ACK);

#3. Make sure this is considered a Number data type in Losant.

#4. Make sure you follow what I did in the Function & Device state notes I show above.

#5. This thread should help you understand how snprintf works for formatting the data your sending to Losant to have the semi-colon in between every variable we send.


#10

I (obviously) second @RWB’s suggestion to use char arrays instead of String.

Just one note about the readability of very long snprintf() lines.

  snprintf(publishStateString, sizeof(publishStateString), "%.2f:%.2f:%.2f:%u:%.2f:%.2f:%u:%u:%.2f:%u:%.2f:%.2f:%.2f:%.2f:%u:%u:%.2f:%.2f:%.2f:%.2f:%.2f:%.2f:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:%u:",bms.GetVoltage(),bms.GetCurrent(),bms.GetCurrent() * bms.GetVoltage(),bms.RelativeSOC(),(bms.AverageTimeTillEmpty()/60),(bms.RemainingBatteryCapacity() - bms.FullBatteryCapacity()) / (bms.GetCurrent() *1000),bms.RemainingBatteryCapacity(),bms.FullBatteryCapacity(),(bms.GetTemp()* 9 / 5 + 32),bms.CycleCount(),bms.CellVoltage1(),bms.CellVoltage2(),bms.CellVoltage3(),bms.CellVoltage4(),bms.StateOfHealth(),bms.MaxError(),mppt.GetSolarInputVoltage(),mppt.GetSolarInputCurrent(),mppt.GetLTC4015BatVReading(),mppt.GetLTC4015BatIReading(),mppt.GetLTC4015BatIReading() * mppt.GetLTC4015BatVReading(),(((mppt.GetLTC4015DieTemp() -12010)/45.6) *9.0 / 5.0 + 32.0),0,0,0,0,0,0,0,0,ChgFet,DsgFet,ShutdownLoVoltage,DischargingDisabled,ChargingDisabled,SleepMode,CellBalancing,0,ChargeInhibit,ChargeSuspend,ChargeTermination,0,0,0,0,0,CellUnderVoltage,CellOverVoltage,0,0,0,OverloadDuringDischargeLatch,0,ShortCircuitDuringDischargeLatch,OvertemperatureDuringCharge,OvertemperatureDuringDischarge,UndertemperatureDuringCharge,UndertemperatureDuringDischarge,CxChargeTerm,NtcPause,ChargerSuspended,AbsorbCharge,ConstantVoltage,ConstantCurrent,LinLimitActive,VinUvClActiveMPPT,VinHiEnoughToCharge,VinOverVoltageLockout,ThermalShutdown,OKToCharge,ChargerEnabled );

I think we can agree that this is rather hard to follow which field is going where
So you could write the same thing like this

  snprintf(publishStateString, sizeof(publishStateString),
           "%.2f:%.2f:%.2f:"
           "%u:%.2f:%.2f:"
           "%u:%u:%.2f:"
           "%u:%.2f:%.2f:"
           "%.2f:%.2f:%u:"
           "%u:%.2f:%.2f:"
           "%.2f:%.2f:%.2f:"
           "%.2f:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:%u:"
           "%u:%u:"
           , bms.GetVoltage(), bms.GetCurrent(), bms.GetCurrent() * bms.GetVoltage()
           , bms.RelativeSOC(), (bms.AverageTimeTillEmpty()/60),(bms.RemainingBatteryCapacity() - bms.FullBatteryCapacity()) / (bms.GetCurrent() *1000)
           , bms.RemainingBatteryCapacity(), bms.FullBatteryCapacity(), (bms.GetTemp()* 9 / 5 + 32)
           , bms.CycleCount(), bms.CellVoltage1(), bms.CellVoltage2()
           , bms.CellVoltage3(), bms.CellVoltage4(), bms.StateOfHealth()
           , bms.MaxError(), mppt.GetSolarInputVoltage(), mppt.GetSolarInputCurrent()
           , mppt.GetLTC4015BatVReading(), mppt.GetLTC4015BatIReading(), mppt.GetLTC4015BatIReading() * mppt.GetLTC4015BatVReading()
           , (((mppt.GetLTC4015DieTemp() -12010)/45.6) *9.0 / 5.0 + 32.0), 0, 0
           , 0, 0, 0
           , 0, 0, 0
           , ChgFet, DsgFet, ShutdownLoVoltage
           , DischargingDisabled, ChargingDisabled, SleepMode
           , CellBalancing, 0, ChargeInhibit
           , ChargeSuspend, ChargeTermination, 0
           , 0, 0, 0
           , 0, CellUnderVoltage, CellOverVoltage
           , 0, 0, 0
           , OverloadDuringDischargeLatch, 0, ShortCircuitDuringDischargeLatch
           , OvertemperatureDuringCharge, OvertemperatureDuringDischarge, UndertemperatureDuringCharge
           , UndertemperatureDuringDischarge, CxChargeTerm, NtcPause
           , ChargerSuspended, AbsorbCharge, ConstantVoltage
           , ConstantCurrent, LinLimitActive, VinUvClActiveMPPT
           , VinHiEnoughToCharge, VinOverVoltageLockout, ThermalShutdown
           , OKToCharge, ChargerEnabled);

Still a massive statement, but a bit easier to conceptualise IMO.


#11

Yea, it’s a beast to try to follow :smile:

I actually created a spreadsheet to keep track of it all which helped.

I was surprised how much data I was able to pack into a single Publish Event using the semi-colon spacing as the separator.


#12

Thank you @RWB and @ScruffR. I will change the code, flash using CLI, then work on the losant end and let you know if…when, I get stuck. :slight_smile:


#13

Happy Monday @RWB and @ScruffR

Something is not right… or I did something wrong.

The data is showing correctly on my OLED Screen but the data being published is the second value in the MAP.

Here is the code.

Before setup I a have added.

char publishStateString[256]; //This is used to hold the device status info we format and Particle Publish to Losant.

void setup() {
    inputBoard.setAddress(0);

In loop I have the following code.

float flow = map(adc,2139.0, 10614.0, 0.0, 200.0);
String F = String::format("%.1f", flow);
  
if (Particle.connected() && millis()-lastpub > 60000) {
		lastpub = millis();
//New Publish CODE

snprintf(publishStateString, sizeof(publishStateString), "%.2f:",F );
Particle.publish("EF", publishStateString, 60, PRIVATE, NO_ACK);

}

Now I tried it with both %.1f and %.2f just to make sure it was not a conflict in data format but I am only publishing the 10614 value, not the mapped value or even the correct value, regardless of flow. Like I said it shows correctly on my OLED just not in the console.

What the heck did I do wrong here?


#14

I think it has to do with you declaring the F variable a String for the OLED display.

Replace the new publish code with this and see what happens:

snprintf(publishStateString, sizeof(publishStateString), "%.2f:",flow );
Particle.publish("EF", publishStateString, 60, PRIVATE, NO_ACK);

#15

yup that was it.

Thank you. I will start to work on Losant now and follow your original instructions. Will keep you posted.

Thanks again for all your help.

Cheers.
Tom