JSON/REST API released

Flukso announces the immediate availability of its JSON/REST API at the 2010 CeBit exhibition in Hannover. Fluksonians are now able to retrieve time series data of their electricity sensors through the Flukso API. Let's start with a working example:

curl -k -v -X GET -H "Accept: application/json" -H "X-Version: 1.0"
-H "X-Token: d8a8ab8893ea73f768b66b45234b5c3a"
"https://api.flukso.net/sensor/c1411c6b4f9910bbbab09f145f8533b9?interval=hour&unit=watt"

Where:

  • X-Version: Denotes the desired API version. Should be set to 1.0.
  • X-Token: A token associated with the specific sensor id. Different tokens per sensor will allow for varying access permissions, e.g. only allow data in 'month' resolution. This feature will become available in the near future. We now provision a single token per sensor. The token can be found next to its respective sensor id (see below).
  • Sensor: Your sensor id's are displayed under the 'my account' -> 'sensor' tab. Just substitute the above sensor id and token with your own and you're ready to go.
  • Interval: Should be one of {hour, day, month, year, night}
  • Unit: Should be one of {watt, kwhperyear, eurperyear, audperyear}

Data is returned as an array of [unix timestamp, value] tuples, where value will be reported as a "nan" string when no data is available for the interval.

[[1267802160,69], [1267802220,69], [1267802280,73], ... , [1267805760,"nan"]]

The unix timestamp denotes the end of the interval for which the value is reported. So in the above example [1267802220,69] means that in the one-minute interval [1267802160, 1267802220] 69 watts of electricity has been consumed.

Thanks to Geert and Mathias for their valuable feedback during alpha testing.

Have fun!

Update 15/03/10: Added info on where to retrieve token information.

Comments

gonium's picture

Hi Bart,

great work! The Ruby Flukso library I've written is here:

Documentation is currently an issue. You can install the library using rubygems:

  1. $ gem install flukso4r

Have a look at the various flukso_* commands. If you have any questions, just ask.

Cheers,
-Mathias

PS: Cebit was indeed fun, and profit!

flok's picture

It would be nice if the JSON thingy comes available in the device itself as well!

icarus75's picture

Hi Flok,

A local Fluksometer JSON/REST interface is in the works. The initial commit adapting the daemon code to publish the sensor measurements of the most recent minute with a one-second resolution can be found here. The basic functionality is up and running in a test setup. We're able to call the local API from a Javascript-based graph which refreshes every second. The code currently doesn't accept any query parameters in the HTTP GET call. So there's still some work to do. We're planning to roll this functionality in a new Fluksometer release based on OpenWRT Backfire.

Cheers,
Bart.

waaij's picture

Hi Bart,

Great to be able to access the data from the flukso site. Accessing it from java took a bit more effort because the default java environment does not have your (root) certificate. Installing that would be an option, but that must be done in each JVM on each computer i want to run my code on. Not what i wanted.

Or... bypass the security :-)

So i have written a small program which installs an "all accepting" trust manager to make the https call. Further more i am using the google simple json library to parse the result.

Hopefully for anyone easy to extend into their own java program.

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. import java.net.URL;
  5. import java.security.SecureRandom;
  6. import java.security.cert.CertificateException;
  7. import java.security.cert.X509Certificate;
  8.  
  9. import javax.net.ssl.HostnameVerifier;
  10. import javax.net.ssl.HttpsURLConnection;
  11. import javax.net.ssl.KeyManager;
  12. import javax.net.ssl.SSLContext;
  13. import javax.net.ssl.SSLSession;
  14. import javax.net.ssl.TrustManager;
  15. import javax.net.ssl.X509TrustManager;
  16.  
  17. import org.json.simple.JSONArray;
  18. import org.json.simple.JSONValue;
  19.  
  20.  
  21. /**
  22.  * Test class to make an UNSECURE call to the flukso site.
  23.  * But this is easier than getting the certificate in the java certificate store ;-)
  24.  * And we trust Flukso :-)
  25.  *
  26.  * JSON library can be found at: <a href="http://code.google.com/p/json-simple/<br />
  27. " title="http://code.google.com/p/json-simple/<br />
  28. ">http://code.google.com/p/json-simple/<br />
  29. </a> * Download the  json_simple-1.1.jar and put in your classpath
  30.  *
  31.  * @author Bram van der Waaij
  32.  *
  33.  */
  34. public class FluksoJSONTest {
  35.         private String sensor = "<your sensorid>";
  36.         private String token = "<your token>";
  37.  
  38.        
  39.         public static void main(String[] args) {
  40.                 new FluksoJSONTest();
  41.         }
  42.        
  43.        
  44.         public FluksoJSONTest() {
  45.                 printWatts(sensor, token, "hour");
  46.                 printWatts(sensor, token, "day");
  47.                 printWatts(sensor, token, "month");
  48.         }
  49.  
  50.  
  51.         /**
  52.          * Print the watt usage of the given sensor/token combination
  53.          *
  54.          * @param sensor
  55.          * @param token
  56.          * @param interval
  57.          */
  58.         public void printWatts(String sensor, String token, String interval)
  59.         {
  60.                 try {
  61.                         String jsonResult = callFlukso(sensor, token, interval, "watt");
  62.                         System.out.println("flukso hour/watt");
  63.                         printJSONResult(jsonResult);
  64.                 } catch (IOException e) {
  65.                         System.out.println("Can not contact the flukso site "+e.getMessage());
  66.                 }
  67.         }
  68.  
  69.        
  70.        
  71.         /**
  72.          * make the https call to the flukso site
  73.          *
  74.          * @param sensor
  75.          * @param token
  76.          * @param interval
  77.          * @param unit
  78.          * @return
  79.          * @throws IOException
  80.          */
  81.         protected String callFlukso(String sensor, String token, String interval, String unit)
  82.                 throws IOException
  83.         {
  84.                 // the url to call flukso
  85.                 String url = "https://api.flukso.net/sensor/" + sensor + "?interval="+interval+"&unit="+unit;          
  86.                
  87.                 try {
  88.                         //make htps context which accepts all certificates
  89.                         SSLContext ctx = SSLContext.getInstance("TLS");
  90.                 ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom());
  91.                 SSLContext.setDefault(ctx);
  92.  
  93.                 // make https connection which accepts any host
  94.                         URL urlHandler = new URL(url);
  95.                         HttpsURLConnection huc = (HttpsURLConnection) urlHandler.openConnection();
  96.                         huc.setHostnameVerifier(new HostnameVerifier() {
  97.                     @Override
  98.                     public boolean verify(String arg0, SSLSession arg1) {
  99.                         return true;
  100.                     }
  101.                 });
  102.                        
  103.                         // set https paramters to GET json data with the given token
  104.                         huc.setRequestMethod("GET");
  105.                         huc.setRequestProperty("accept", "application/json");
  106.                         huc.setRequestProperty("x-version", "1.0");
  107.                         huc.setRequestProperty("x-token", token);
  108.                        
  109.                         // make te call to flukso
  110.                         huc.connect();
  111.                        
  112.                         // parse response
  113.                         if (huc.getResponseCode() == 200) {
  114.                                 BufferedReader in = new BufferedReader(new InputStreamReader(huc.getInputStream()));
  115.                                 // collect entire response in one string
  116.                                 String result = "";
  117.                                 String line= "";
  118.                                 while ((line = in.readLine()) != null) {
  119.                                         result = result + "\n" + line;
  120.                                 }
  121.                                 return result;
  122.                         } else throw new IOException("Can not communicate with the flukso site (HTTP code="+huc.getResponseCode()+") with URL: "+url);
  123.                 } catch (Exception ex) {
  124.                         throw new IOException("Error ("+ex.getMessage()+") during communicating with URL: "+url);  
  125.                 }
  126.         }
  127.            
  128.        
  129.        
  130.         /**
  131.          * Parse the json string as returned from the flukso site and print the result
  132.          *
  133.          * @param jsonResult
  134.          */
  135.         protected void printJSONResult(String jsonResult) {
  136.                 try {
  137.                         // parse the json string, expect an json-array
  138.                         JSONArray jsonArray = (JSONArray)JSONValue.parse(jsonResult);
  139.                        
  140.                         // loop through the measurements
  141.                         for (int i=0; i<jsonArray.size(); i++) {
  142.                                
  143.                                 // each measurement is an json-array itself
  144.                                 JSONArray measurement = (JSONArray)jsonArray.get(i);
  145.                                
  146.                                 // each measurement should contain 2 elements (timestamp and value)
  147.                                 if (measurement.size() == 2) {
  148.                                         Object timestamp = measurement.get(0);
  149.                                         Object value = measurement.get(1);
  150.                                        
  151.                                         // check if both elements are of the correct type
  152.                                         if ((timestamp instanceof Long) && (value instanceof Long)) {
  153.                                           System.out.println("Timestamp="+timestamp+" value="+value);
  154.                                         } else {
  155.                                                 if (timestamp instanceof Long)
  156.                                                         System.out.println("value not a number ("+value+")");
  157.                                                 else System.out.println("unexpected array format ["+timestamp.getClass().getName()+", "+value.getClass().getName()+"]");
  158.                                         }
  159.                                 } else {
  160.                                         System.out.println("Unknown measurement element size ("+measurement.size()+") should be 2)");
  161.                                 }
  162.                         }
  163.                 } catch (Exception e) {
  164.                         System.out.println("Error during parsing json result from Flukso");
  165.                         e.printStackTrace();
  166.                 }
  167.         }
  168.        
  169.        
  170.         /**
  171.          * Helper class needed to make the https call accepts all sites
  172.          */
  173.         private static class DefaultTrustManager implements X509TrustManager {
  174.         @Override
  175.         public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
  176.  
  177.         @Override
  178.         public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
  179.  
  180.         @Override
  181.         public X509Certificate[] getAcceptedIssuers() {
  182.             return null;
  183.         }
  184.     }
  185.  
  186. }

Have fun,
Bram