I am guessing this is something to do with beer? Brilliant.
@bevangg, Yup. I use BrewPi for fermentation control and can adjust remotely so I figured itâd be nice to have some rough idea of fermentation activity available remotely as well.
About the particle cloud server. Are you suggesting just uploading to the particle dashboard and then have that data pushed to another logging option?
I have the stuff working to ubidots but I had to upgrade to a $12/mo plan to have access to some of the graphing/equation features so Iâm going to start looking into other options. One thing I considered was to just have the program count bubbles for 1 full minute and then upload just the bubbles and then reset the counter. That would be plenty useful for me. Iâm not real sure how to make the loop count bubbles for a minute and then send that total and restart counting but Iâm sure it can be done.
Good project idea. For real-time data you could use blynk but it does not yet log data and you have to be careful not to exceed their limits. As you say if you had your own server you would not have any data limitations other than physical. Hopefully we will soon be able to download data from the dashboard and process it with excel or whatever, again if you had your own cloud server you should be able to access the data somehow.
Your idea of counting for a minute and then sending is a good workaround, all you need to to is create a bubble counter in the loop and a timer, this page might help you to achieve this. Also shows how to avoid delays anywhere in your code, which strikes me as a good idea for a web-connected device.
I was just doing some more research on Blynk and found that you can also set up your own blynk server on a pc or even a pi. No idea how much of a challenge it would be to extract the data from that. That would be nice if you could get it working, you would have live data and be able to control the spark at the same time.
I have been working on that inside counting loop that just publishes every minute and have come up with this. Sadly, itâs not publishing anything. (this is a version that just sends to dashboard). Notice anything wrong with it?
int Gate = D4;
int Led = D7;
int gateState = 0;
int sendDelay = 60000;
int count = 0;
int totalCount = 0;
void setup() {
pinMode(Gate, INPUT);
pinMode(Led, OUTPUT);
Time.zone(-6);
}
void loop() {
unsigned long currentMillis = millis();
static byte prevState = 1;
gateState = digitalRead(Gate);
digitalWrite(Led, LOW);
if(gateState != prevState)
{
if(gateState == HIGH)
{
count = totalCount+1;
digitalWrite(Led, HIGH);
if(currentMillis >= sendDelay)
{
Particle.publish("Bubbles!",
String::format("Time: %s ",
Time.timeStr().c_str(),
totalCount));
totalCount = 0;
currentMillis = 0;
}
}
//else ignore
prevState = gateState;
}
delay(50);
}
Thanks!
I guess you do get two (maybe four) âBubble!â publishes, but no more.
There are some things to be noted.
Max publishing rate is one per second with a burst of four with a four second pause.
And since you are always setting unsigned long currentMillis = millis();
your if(currentMillis >= sendDelay)
will always stay true once the device was running for more than 60 seconds (and after about 59 days when millis()
wraps round youâll get four more publishes ;-))
To do this properly, youâd do something like this
unsigned long msLastPublish;
void loop()
{
static byte prevState = 1;
gateState = digitalRead(Gate);
digitalWrite(Led, LOW);
if(gateState != prevState)
{
if(gateState == HIGH)
{
totalCount++;
digitalWrite(Led, HIGH);
}
//else ignore
prevState = gateState;
}
if(millis() - mmLastPublish >= sendDelay)
{
Particle.publish("Bubbles!",
String::format("Time: %s - %d",
Time.timeStr().c_str(),
totalCount));
totalCount = 0;
msLastPublish = millis();
}
}
Hey, thanks @ScruffR, I was just about to post what I have worked out now.
void loop() {
unsigned long currentMillis = millis();
static byte prevState = 1;
gateState = digitalRead(Gate);
digitalWrite(Led, LOW);
if(gateState != prevState)
{
if(gateState == HIGH)
{
count ++;
digitalWrite(Led, HIGH);
}
prevState = gateState;
}
if(currentMillis - previousMillis >= sendDelay)
{
Particle.publish("Bubbles!",
String::format("Time: %s ",
Time.timeStr().c_str(),
count));
previousMillis = currentMillis;
count = 0;
}
delay(50);
}
It looks pretty similar and seems to workâŚkinda. It post something every 10s (or whatever the interval is) but itâs not publishing any value for count
. It just says âBubbles!â every 10s.
Is it better to have the unsigned long currentMillis = millis();
outside of the loop?
Is there a problem with how I am counting the events or is it more of a problem with how Iâm trying to publish them?
I also tried to use Particle.publish(count);
and received the following errors. I obviously have a very poor understanding of the Particle.publish();
and the formatting stuff. I want to get this project working but I also want to learn so if you have any advice on the current situation and then how to better educate myself on it, I be glad to know.
error: invalid conversion from 'unsigned int' to 'const char*' [-fpermissive]
error: initializing argument 1 of 'bool CloudClass::publish(const char*, Spark_Event_TypeDef)' [-fpermissive]
bool publish(const char *eventName, Spark_Event_TypeDef eventType=PUBLIC)
Nope, this is not required, but if you don't really need millisecond precision, you can even loose the extra variable and directly use millis()
instead, but with the variable you can be sure to always have the same value wherever you use it.
If you look at the Particle.publish()
docs, there are only these possible signatures
Particle.publish(const char *eventName);
Particle.publish(String eventName);
Particle.publish(const char *eventName, const char *data);
Particle.publish(String eventName, String data);
Particle.publish(const char *eventName, const char *data, int ttl);
Particle.publish(String eventName, String data, int ttl);
Particle.publish(const char *eventName, const char *data, int ttl, PRIVATE);
Particle.publish(String eventName, String data, int ttl, PRIVATE);
Particle.publish(const char *eventName, PRIVATE);
Particle.publish(String eventName, PRIVATE);
There is none that accepts a numeric value as eventName
or a data
parameter.
But my sample above shows how to format a data
string containing multiple variables.
Some good read about the formatting syntax can be found here too
http://www.cplusplus.com/reference/cstdio/printf/
So the short answer is that I wonât be about to upload the event count? Is that correct?
No, this is not what I said.
Try my publish code from above and not the difference
Particle.publish("Bubbles!",
String::format("Time: %s - %d",
Time.timeStr().c_str(),
totalCount));
Man, sorry @ScruffR, I didnât even notice the bright red highlighting. That works to display the number of events. Honestly, I have learned a bunch through this project but what you have inside that Particle.publish(voodoo)
; has me all screwed up. Iâm gonna make you proud though!
I worked the counting and delay into my Ubidots one as well and that seems to be a good option for logging too.
Thanks again!
String::format("Time: %s - %d", Time.timeStr().c_str(), totalCount));
Its not so hard! Lets break it downâŚ
String::format - That part is easy, youâre saying you want to format something into a string.
After that, we have three items inside the function (parameters)
The first parameter is the string you ultimately want to create:
Time: %s - %d
//for example: Time: 8:00PM - 43
But! Every time you write %_ youâre saying âReplace this with a string, integer, etcâ
%s -> replace with string
%d -> replace with integer
%f -> replace with float
As the compiler processes your code, it replaces the %s and %d with the next items in your function.
%s is the first variable, so it gets replaced by the first parameter after our string: Time.timeStr().c_str()
%d is the second variable, so it gets replaced by the second parameter after our string: totalCount
Finally, the publish function itself just sends out the information
Particle.publish("Variable Name", "Variable Value");
@johnventions Excellent quick overview of the String::format function. I now understand how it works!
Are these all there are to this function or are there more:
%s -> replace with string
%d -> replace with integer
%f -> replace with float
As posted above
And also here, where you already were - as a direct response to a post of yours
@ScruffRâs link has them all!
@ScruffR Yea I was going to go back to your link once I needed to format an output again and I admit I didnât look at it at the time you posted that but just reading over @johnventions short explanation above I quickly understood what was actually going on which was a Eureka moment
Now with his explination + your link Iâm much better off
Tanks to both of you for helping out the less knowledgeable community! It really makes a BIG difference.
Thanks @johnventions! This explanation was very useful. Combined with what @ScruffR has already explained to me I think I am starting to get it... just maybe.
So for my example, the "Variable Name" is "Bubbles!
" and the "Variable Value" is String::format("Time: %s - %d", Time.timeStr().c_str(), totalCount));
.
And for the Variable Value, we are saying that we want to format the Variable Value into a string.
We type String::format()
to say we are formatting this variable into a string.
We can just type "Time: %s, Time.timeStr().c_str()"
and that will just print "Time: and then replace the %s with the value of Time.timeStr().c_str()
.
We added the - %d
so that it would replace the %d
with the integer value of , totalCount
.
So when you are specifying a parameter for the Variable Value, whenever you put %_
, it goes and looks for that value after the proceding " , ".
Talking aloud here. Does that seem about right? When you have multiple values, do you always separate them with " -
"?
Is there a limit to how many %_
you can use?
Thanks again!
You do not need to use " - " to separate out different parts of the final string. That was just an example.
For instance, you could have formatted it as:
String::format(
"The time is %s and the bubble count is: %d",
Time.timeStr().c_str(),
totalCount
)
And that would print âThe time is ___ and the bubble count is: ___â
It all depends on how you want to process the data after its sent to the Particle Cloud.
If you want to separate out the time and the bubble count afterwards, its usually nice to have some sort of character that tells you when one piece of data starts and the other stops. People will often use â-â, or â_â or â|â for things like that.
Okay, awesome! Man, this is great. So helpful.
Another question!
In void setup()
, I had Time.zone(-6);
and then in the Particle.publish()
, I used %s
to call the Time.timeStr().c_str()
variable. Is this two different time functions" Time.timeStr() and .c_str()
? Or is this simply just one defined way of getting the time formatted/displayed a specific way?
Wait. Is this just saying that you want Time.timeStr()
formatted as a String (.c_str()
)? Seems like the Time.timeStr()
would suggest that itâs already a string?
Truthfully I donât know why you need to use:
Time.timeStr().c_str()
instead of just:
Time.timeStr()
But maybe someone else does here.
Does it work the shorter way? Might as well try it.