User Tools

Site Tools


oak:tutorials:particle-function

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
oak:tutorials:particle-function [2016/03/20 12:07]
jwhendy created
oak:tutorials:particle-function [2016/05/27 01:30] (current)
pfeerick edited to hopefully reduce confusion on how Particle.function is used in code
Line 1: Line 1:
-In this example, we'll show one way you can make the data sent by the Oak useful with ''​python''​. You can install python as described in [[oak:tutorials:​serialfirmware|the firmware over serial]] tutorial. Make sure for the below that you'​re ​using ''​python''​ version 2.(e.g. 2.7), not ''​python''​ v3.+===== Oak: using Particle.function() =====
  
-==== The circuit ====+This tutorial is very similar to the one on [[http://​digistump.com/​wiki/​oak/​tutorials/​particle-variable|Particle.variable()]]. This time, however we will be doing the reverse: //sending// data to the Oak. To accomplish this, we use ''​Particle.function()''​. As an example, we will send ''​POST''​ commands using ''​curl''​ to the Particle API which will control the color of an RGB led connected to the Oak.
  
-This tutorial ​will utilize a TMP36 analog temperature sensorbut anything that can generate ​changing value read by the Oak will work. The circuit is quite simple:+In addition to this tutorial, ​please do take look at the [[https://​docs.particle.io/​reference/​firmware/​core/#​particle-function-|official documentation]].
  
-[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​fritz-tmp36-battery.png|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​fritz-tmp36-battery.png?​400|}}]] 
  
-Here's the setup in real life, with the outer TMP36 pins plugged directly into Vcc and ground, and a soldered jumper connecting the middle pin to ''​A0''​. It's connected to power using a surplus store 4 x AA battery pack. 
  
-[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​tmp36-hookup.jpg|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​tmp36-hookup.jpg?​400}}]]+===== Components used =====
  
 +^Part ^Quantity ^Identification^
 +|Oak with soldered headers| 1 | |
 +|Breadboard| 1 | |
 +|Jumper wires | 4 | |
 +|RGB LED| 1 | whitish LED with 4 leads, one longer than the others |
 +|Resistor, 220 ohm| 3 | Red-Red-Brown|
  
-==== Code on the Oak ====+These are the same components used with the [[http://​digistump.com/​wiki/​oak/​tutorials/​rgb-led#​components_used|RGB LED tutorial]]. Feel free to substitute any resistor value between 100-1k ohms.
  
-To read the temperature,​ we'll convert the analog reading to millivolts and then to degrees Celsius as described in [[https://learn.adafruit.com/tmp36-temperature-sensor/​using-a-temp-sensor|this Adafruit tutorial]]. The variable will be accessible through ​the ''​Particle.variable()''​ function, which we'll read with ''​python''​ and then use to email a notification when it falls below a certain level.+**Note:** You need to install ​[[https://curl.haxx.se/download.html|curl]] to push data to the Particle ​API.
  
-Here's the Oak code:+===== Concepts =====
  
-<​code>​ +=== Particle.function() ===
-double tempC 0; +
-int analog ​0; +
-double mv;+
  
-void setup() +This function creates an interface between your Oak and particle.io. We create a function with a given name, and then access that named function via ''​curl''​ commands, passing along a value with it. On the Oak side, it finds the function with that name, and then runs it with the value that was passed.
-{                ​+
  
-  // the Particle.variable() function ​takes two arguments:​ +The syntax looks like ''​Particle.function("​name",​ function_name)'',​ and you then have a function ​that look like the below example, which is run when the function ​is triggered. You would normally place the ''​Particle.function''​ command in the setup(portion of your code. Have a look at the example sketch at the bottom of the page to better understand how function is used.
-  // 1) the name of the Particle variable. This is how you interact +
-  //    with the Particle ​cloud to access ​the value +
-  // 2) the local variable name to be stored in the cloud variable +
-  Particle.variable("​temp",​ tempC);+
  
-  // we'll configure the on-board LED to blink +<​code>​ 
-  // this is handy for simply making sure the Oak is running your sketch +int function_name(String arg)
-  pinMode(1, OUTPUT); +
-  digitalWrite(1,​ LOW); +
-  pinMode(A0, INPUT); +
-   +
-+
- +
- +
-void loop()+
 { {
  
-  // with the tmp36, the temperature is found using this formula: +  // code goes here 
-  ​// temp in C = (millivolts out - 500)/10 +  ​Serial.print(arg);
-  // we're reading an analog value (0-1023) which is proportional +
-  // to the analog reference voltage, which on the Oak is 3.3v for Vcc.+
  
-  // get the analog value 
-  analog = analogRead(A0);​ 
- 
-  // convert to millivolts 
-  // if your temperature readings are incorrect; adjust the 2700 value below 
-  // this *should* be 3300 for a 3.3V analog device, however plain and simple 
-  // the temperature may be incorrect and you can use it to calibrate 
-  mv = analog * 2700.0 / 1024.0; 
-    ​ 
-  // convert from mV to degrees C 
-  tempC = (mv - 500.0) / 10.0; 
-  
-  // flash the LED 
-  digitalWrite(1,​ HIGH); 
-  delay(100); 
-  digitalWrite(1,​ LOW); 
-  delay(500); 
-  ​ 
 } }
 </​code>​ </​code>​
  
-After uploading ​this sketch, we can do a test call to the Particle API as described in the [[oak:​tutorials:particle-variable|Particle.variable() tutorial]]. +We would access this function like this:
- +
-==== Testing the code ====+
  
 <​code>​ <​code>​
-curl https://​api.particle.io/​v1/​devices/​id_here/temp?​access_token=token_here +curl https://​api.particle.io/​v1/​devices/​id_goes_here/name/ \ 
-+  ​-d access_token=token_goes_here 
-  "​cmd":​ "​VarReturn",​ +  -"args=hello"
-  "name": "​temp",​ +
-  ​"​result":​ 19.609375, +
-  ​"​coreInfo":​ { +
-    "​last_app":​ "",​ +
-    "​last_heard":​ "2016-03-20T17:​44:​21.275Z"+
-    ​"connected":​ true, +
-    "​last_handshake_at":​ "​2016-03-20T17:​43:​52.080Z",​ +
-    "​deviceID":​ "​12345678",​ +
-    "​product_id":​ 82 +
-  }+
 </​code>​ </​code>​
  
-==== Reading ​the Particle ​URL with python ====+The Oak would print "​hello"​ when this ''​curl''​ command is sent (which puts ''​name''​ from above in the URL, //not// function_name). When the Oak receives the call to ''​name'',​ it runs the associated function (''​function_name''​),​ and passes along a ''​String''​ (and only a ''​String''​) which we called ''​arg''​.
  
-With that working properlylet'​s ​go about reading that data from computer using ''​python''​. For the utter basics, we need to import ​''​urllib''​ and ''​json''​ to get the API response and read it in. We've added some other modules in order to delay a loop (''​time'')get the current time (''​datetime''​), and send an email (''​smtplib''​ and ''​MIMEText''​)The core of the functionality is simply in getting and parsing the data:+This might seem complicatedbut it'​s ​fairly straightforward. Let's connect ​circuit and test it out! 
 + 
 +=== indexOf() === 
 + 
 +In the second code example, we will use the Arduino function ​''​indexOf()''​ to parse multiple values sent to particle.io ​in one StringThe function works on the ''​String'' ​//class//so you append it to the name of the ''​String'' ​variable. Let's say we have a variable called ​''​theString''​ and it contains "​a,​b,​c"​You could find the location ​of "​b"​ with:
  
 <​code>​ <​code>​
-## import what we need +theString.indexOf("​b"​);​ 
-import urllib +</​code>​
-import json+
  
-## simplify ​the url bit +You can also tell the function not to start looking until certain locationRemember that the first character in the string is 0This handy if you have multiple repeating charactersIn that case, the function is ''​theString.indexOf("thing_to_find", position_to_start_looking).''​
-base = "​https://​api.particle.io/​v1/​devices/"​ +
-device_id = "​device_id_here"​ +
-token = "​token_goes_here"​ +
-var = "/​temp"​ ## change this if you used a different Particle.variable() name +
-option = "?​access_token="+
  
-## put together the full url to query +=== substring() ===
-url base + device_id + var + option + token+
  
-# opens/reads the URL and then parses the json response +Using ''​substring()''​ in combination with ''​indexOf()''​ will let us send one long ''​String''​ with values separated by commas (or some other character) and extract them one at a time. Below, we will use this strategy to send the RGB values in one shot instead of using ''​Particle.function()''​ three separate times.
-data = urllib.urlopen(url).read() +
-data_json = json.loads(data)+
  
-## gets the json value under the "​result"​ key +It works like this: 
-temp round(float(data_json["result"​])2)+<​code>​ 
 +String theString ​= "a,b,c";
  
-print temp+// variables to hold each thing we want to extract 
 +String char1, char2; 
 + 
 +// the positions of each thing 
 +int loc1, loc2; 
 + 
 +// find first comma, then take the string from the start to the comma'​s location 
 +loc1 = theString.indexOf(","​);​ 
 +char1 = theString.substring(0,​ loc1); 
 + 
 +// now we start at one character *past* the first comma and look again 
 +// we extract the characters between the last comma we found and the next one we find 
 +loc2 = theString.indexOf(",",​ loc1 + 1); 
 +char2 = theString.substring(loc1 + 1, loc2);
 </​code>​ </​code>​
  
-Each time you run the code above, ''​python''​ will print the value stored ​in ''​results'', ​which corresponds to our call for the ''​temp'' ​variable defined by ''​Particle.variable()'':​+We could continue ​in this pattern for as many commas as we know are present. When we use ''​substring(start,​ stop)'', ​it just pulls out the characters from that range of positions from the larger ​''​String''​
 + 
 +===== Circuit ===== 
 + 
 +Please complete the circuit used in the [[http://​digistump.com/​wiki/​oak/​tutorials/​rgb-led|RGB LED tutorial]]. 
 + 
 +[[http://​digistump.com/​wiki/​_media/​oak-rgb-led.png|{{http://​digistump.com/​wiki/​_media/​oak-rgb-led.png?​400}}]] 
 + 
 +===== Code ===== 
 + 
 +=== Code: setting colors === 
 + 
 +The following code will create ​''​Particle.function()''​s in order to allow setting of each channel of an RGB LED:
  
 <​code>​ <​code>​
-## I have this script saved as temp-get.py +// variables to store the brightness of each color channel of the RGB LED 
-$ python ./temp-get.py +int bright_r = 0; 
-19.84+int bright_g = 0; 
 +int bright_b = 0;
  
-$ python ./​temp-get.py +void setup() 
-20.14 +{                ​
-</​code>​+
  
-==== Sending an email with python ====+  // Particle.function() takes two arguments:​ 
 +  // 1) the name to reference in the URL with curl 
 +  // 2) the function name run when the reference name is called\ 
 +  Particle.function("​r",​ set_r); 
 +  Particle.function("​g",​ set_g); 
 +  Particle.function("​b",​ set_b);
  
-With that behavingyou can put ''​python''​ to workchecking the temperature with some frequency and doing something in response. We'll imagine you might want to check if something gets down to a certain low temperature and then email you about it. Real life examples might be:+  // initialize each color pin as an output 
 +  pinMode(6OUTPUT); 
 +  pinMode(7OUTPUT); 
 +  pinMode(8, OUTPUT); 
 +   
 +}
  
-  * letting you know it's near freezing so you can cover your plants and protect from frost +// for each Particle.function() definition above 
-  * an alert about the pipes at cabin so you can wirelessly turn on the heat +// we create ​matching function 
-  * a notification that your beer in the freezer is now cold so you don't forget ​and have it explode ​in your ice tray...+// it will take the argument passed with curl (always a String variable),​ 
 +// convert it to an integer, ​and store it in that color'​s variable 
 +// lastly, it will send that setting to that color'​s pin to change the color 
 +int set_r(String arg) 
 +
 +  bright_r = arg.toInt(); 
 +  analogWrite(6,​ bright_r);  
 +}
  
-The algorithm we're looking forthen, is:+int set_g(String arg) 
 +
 +  bright_g = arg.toInt();​ 
 +  analogWrite(7bright_g);  
 +}
  
-  * get the temperature +int set_b(String arg) 
-  * log the current time and temperature in a log file +{ 
-  ​* see if it's below a cut off +  ​bright_b = arg.toInt();​ 
-  ​* if sosend an email and quit +  ​analogWrite(8bright_b); ​ 
-  * if not, wait little bit (no sense reading once a second here) and repeat+
 + 
 +// we don't even need loop() section! The Oak will 
 +// essentially wait for a call to one of the above functions 
 +// and spring into action when it comes through 
 +void loop() 
 +{  
 +
 +</​code>​
  
-If we move the code above into a ''​while''​ loopwe can accomplish this flow like so:+Upload the sketch, and test it out! If all is well, the RGB LED should start out completely off. Try turning on each colorone at a time:
  
 +This will turn on red; we're calling the Particle function named "​r",​ and sending the value 1023.
 <​code>​ <​code>​
-## import what we need +                 function name to call is here ----|          
-## added in time and email requirements +                                                     | 
-import urllib +curl https://​api.particle.io/​v1/​devices/​id_goes_here/​r \ 
-import json +    -d access_token=token_goes_here 
-import smtplib +    -d "​args=1023"​ 
-import datetime +               | 
-from time import sleep +# value sent --| 
-from email.mime.text import MIMEText+</​code>​
  
-## simplify ​the url a bit +When this URL is sent, it triggers ​the Oak to run the ''​set_r''​ function, which converts our ''​String''​ ("1023") to number, and sets the red channel of the LED to that value (full red).
-base = "https://​api.particle.io/​v1/​devices/​" +
-device_id = "​device_id_here"​ +
-token = "​token_goes_here"​ +
-var = "/​temp"​ ## change this if you used different Particle.variable() name +
-option = "?​access_token="​+
  
-## put together ​the full url to query +Now we'll turn on green, which will make the color yellowish. 
-url base + device_id + var + option + token+<​code>​ 
 +                 # function name to call is here ----|          
 +                                                     | 
 +curl https://​api.particle.io/​v1/​devices/​id_goes_here/​g \ 
 +    -d access_token=token_goes_here 
 +    -d "​args=1023"​ 
 +               | 
 +# value sent --| 
 +</​code>​
  
-# initialize a variable so we know when to stop the loop +Keep playing around with different function names and brightness values. What happens if you try to send nonsense like the letter ''​a''?​ Set a color to 0, send a letter, and observe the result. Repeat after setting to to 1023. Why does that happen ([[https://​www.arduino.cc/​en/​Reference/​StringToInt|hint!]]?​
-email = 0+
  
-# as long as email is 0, run the below again and again +=== Codesending multiple values ===
-while email == 0:+
  
-    # same code as above; get URL data, convert ​to json and extract temp +What if you wanted direct access to all three key variables without having ​to call separate functions? The ''​Particle.function()''​ [[https://​docs.particle.io/​reference/​firmware/​core/#​particle-function-|documentation]] states that only //one// ''​String''​ value may be passed with the call.
-    data = urllib.urlopen(url).read() +
-    data_json = json.loads(data)+
  
-    temp = round(float(data_json["​result"​]), 2)+Thankfully there are ways to split apart a ''​String''​ if you know the structure. There are several examples of various ways to pass multiple values to ''​Particle.function()''​ if you [[https://​www.google.com/​webhp?​sourceid=chrome-instant&​ion=1&​espv=2&​ie=UTF-8#​q=pass%20multiple%20parameters%20to%20particle.function|search for them]]. We will use the one described [[https://​community.particle.io/​t/​rest-api-arguments-is-there-a-better-way/​960/​2|here]].
  
-    # store the current system time for this reading +<​code>​ 
-    ​now ​datetime.datetime.now().strftime("​%Y-%m-%d-%H:​%M:​%S"​)+// each color'​s brightness 
 +int bright_r = 0; 
 +int bright_g = 0; 
 +int bright_b ​0;
  
-    # define some cutoff; if the temperature is below 5C, do this: +// locations of the commas we'll find below 
-    if temp < 5 : +int loc1 0
-     +int loc2 0; 
-        # this composes the message +int loc3 0;
-        msg MIMEText("​The beer is coldit's " + str(temp) + " C!") +
-        ​addy ​"​your_email_address@here.com"​ +
-        ​msg["​Subject"​] ​"Get to the freezer!"​ +
-        msg["​From"​] = addy +
-        msg["​To"​] = addy+
  
-        # this will send an email from you, to you, through your smtp server +void setup() 
-        # google your email provider and "smtp settings"​ to find out yours +{                ​
-        print "​emailing..."​ +
-        smtpserver = smtplib.SMTP("​smtp.gmail.com",​ 587+
-        ​smtpserver.ehlo() +
-        smtpserver.starttls() +
-        smtpserver.ehlo() +
-        smtpserver.login(addy,​ "​your_email_password"​) +
-        smtpserver.sendmail(addy,​ addy, msg.as_string()) +
-        smtpserver.close()+
  
-        # now we set email to 1 so the while loop stops +  // just one function! 
-        email = 1+  Particle.function("​set", set_rgb); 
 +   
 +  // initialize each color pin as an output 
 +  pinMode(6, OUTPUT); 
 +  pinMode(7, OUTPUT); 
 +  pinMode(8, OUTPUT); 
 +  ​ 
 +}
  
-    # each time through, add the time and temperature to a file +int set_rgb(String arg
-    # you may have to create this file if it doesn'​t exist +{
-    log = open("/​path/​to/​tmp36_data-log.csv",​ "​a"​+
-    ​log.write(str(temp) + ","​ + now + "​\n"​) +
-    log.close()+
  
-    # wait 10 seconds and repeat +  // find the location of the first comma 
-    sleep(10)+  // extract from 0 to the comma, storing the value 
 +  // as an integer 
 +  loc1 = arg.indexOf(","​);​ 
 +  bright_r = arg.substring(0,​ loc1).toInt();
  
-# when all done (email sent), tell us +  // find the next comma by searching starting at the last one 
-print "done"+  // extract from the last comma to this one 
 +  // store as an integer in bright_g 
 +  loc2 = arg.indexOf(",",​loc1+1)
 +  bright_g = arg.substring(loc1+1loc2).toInt();​ 
 + 
 +  // repeat, taking the value between the last comma and this one 
 +  loc3 = arg.indexOf(",",loc2+1); 
 +  bright_b = arg.substring(loc2+1,​ loc3).toInt();​ 
 + 
 +  // write all three values to their respective color pins 
 +  analogWrite(6,​ bright_r);​ 
 +  analogWrite(7,​ bright_g);​ 
 +  analogWrite(8,​ bright_b);​ 
 +   
 +
 + 
 +void loop() 
 +{  
 +}
 </​code>​ </​code>​
  
-Unfortunatelylong wires on the TMP36 thwarted my attempts to record ​an actual beer's temperature in my freezerso I simply put the bundle out on my porch (Minnesota). The nice part about storing the data to a local log file is you can plot it easily by importing the ''​csv''​ formatted ​file into ExcelLibreOfficeetc.+With only one function that can extract three values separated by commaswe can now pass an ''r,g,b''​ formatted ​argument and have all three colors changed in one shot: 
 + 
 +<​code>​ 
 +curl https://​api.particle.io/​v1/​devices/​id_goes_here/​set \ 
 +    -d access_token=token_goes_here 
 +    -d "​args=1023,0,512" 
 +</​code>​
  
-[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​temp-plot.png|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​temp-plot.png?​600}}]]+That will turn on red all the way and blue halfway, creating a pinkish colorPlay around with other value combinations and set some colors!
  
-Based on the temperature outside, I adjusted the cutoff to 11C (''​if temp < 11''​ above) after I saw it wasn't going to drop below 10C. Here's what I got!+===== Conclusion =====
  
-[[http://​digistump.com/​wiki/​_media/​oak/​tutorials/​python-email-notify.png|{{http://​digistump.com/​wiki/​_media/​oak/​tutorials/​python-email-notify.png?​400}}]]+And that's it for the basics of sending data with ''​curl''​ via particle.io! We learned how to pass values, as well as to utilize one ''​Particle.function()''​ to set many values by sending them in a known format, combined with ''​indexOf''​ and ''​substring()''​ to separate them from one another
  
 +It's up to you what you send, and how you have the Oak respond to it. For one idea, check out the tutorial on using ''​python''​ to generate or collect data (say, from a local sensor) and send it to the Oak. The nice thing with these functions is that if you can do something on the Oak, you can make it happen when a command is sent with ''​Particle.function()'';​ it's just a matter of slightly re-arranging your code.
oak/tutorials/particle-function.1458500857.txt.gz · Last modified: 2016/03/20 12:07 by jwhendy