This program will use cURL library for C++ and c++11 compiler, which is gcc-4.7 in this example.
pi@desktoppi ~ $ sudo apt-get install libcurl4-openssl-dev pi@desktoppi ~ $ sudo apt-get install g++-4.7
pi@desktoppi 01:06:01 hue$ ls hue.cpp Makefile my_curl.hpp stdafx.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | // hue.cpp written by JaeHyukKwak #include "stdafx.h" #include "my_curl.hpp" static const char *MAC_HUE = "00:17:88:09:ef:18"; static string ip_hue = "192.168.0.50"; int main( int argc, const char **argv ) { if ( argc == 1 ) { cerr << "Usage: " << argv[0] << " light#" << endl; cerr << " or " << argv[0] << " light# key value" << endl; cerr << "Example#1: " << argv[0] << " 1 on true" << endl; cerr << "Example#2: " << argv[0] << " 2 bri 255" << endl; cerr << "Example#3: " << argv[0] << " 3 hue 65535" << endl; return 1; } bool readOnly = ( argc == 2 ); for ( ifstream fin( "/proc/net/arp" ); !fin.eof(); ) { // ex: 192.168.0.53 0x1 0x0 f4:7b:5e:41:91:00 * eth0 string line; getline( fin, line ); if ( line.find( MAC_HUE ) == string::npos ) continue; ip_hue = line.substr( 0, line.find( ' ' ) ); break; // IP address for HUE is found. } const char *lightIndex = argv[1]; string URL_base = "http://"; URL_base += ip_hue + "/api/newdeveloper/lights/" + lightIndex; string URL = URL_base + ( readOnly ? "" : "/state" ); my_curl_t curl; curl.SetOpt_URL( URL ); if ( readOnly ) cout << curl.RequestGet() << endl; else { const char *key = argv[2]; const char *value = argv[3]; string cmd = string( "{\"" ) + key + "\":" + value + "}"; curl.SetOpt_READDATA( cmd ); cout << curl.RequestPut() << endl; } } |
The program check the command arguments. If it doesn't have any command arguments, it prints out how to use it. It expects to have a light bulb number. It will return the status of the light bulb. When additional two more arguments are given, they will be used to change the status of the light bulb; first one will be used as a key and the second will be used as a value. Unlike the script version I presented, this doesn't handle error cases like when you haven't created user name; BTW, this example assumes that the user name on the Hue Bridge is "newdeveloper".
The Makefile will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 | # Makefile written by Jae Hyuk Kwak CC=g++-4.7 CFLAGS=-Wall -g -std=c++11 hue: hue.cpp my_curl.hpp stdafx.h.gch $(CC) $(CFLAGS) -lcurl -o hue hue.cpp stdafx.h.gch : stdafx.h $(CC) $(CFLAGS) -c stdafx.h clean: rm stdafx.h.gch hue |
1 2 3 4 5 6 7 8 9 10 | // stdafx.h written by JaeHyukKwak #include <string> #include <iostream> // cout, cerr #include <fstream> // ifstream #include <stdexcept> // runtime_error #include <memory> // unique_ptr #include <string.h> // memcpy using namespace std; #include <curl/curl.h> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | // my_curl.hpp written by JaeHyukKwak class my_curl_t { unique_ptr< CURL, decltype( curl_easy_cleanup )* > curl_; string html_; // temporary buffer to store HTML content string put_; // temporary buffer to store PUT content public: my_curl_t() : curl_( curl_easy_init(), curl_easy_cleanup ) { if ( nullptr == curl_ ) throw runtime_error( "curl_easy_init() failed." ); SetOpt_( CURLOPT_WRITEDATA, &html_ ); SetOpt_( CURLOPT_WRITEFUNCTION, WriteMemoryCallback ); SetOpt_( CURLOPT_READDATA, &put_ ); SetOpt_( CURLOPT_READFUNCTION, ReadDataCallback ); } string RequestGet() { return Request_( 0 ); } string RequestPut() { return Request_( 1 ); } void SetOpt_READDATA( string data ) { put_ = data; } void SetOpt_URL( string url ) { SetOpt_( CURLOPT_URL, url.c_str() ); } private: string Request_( int post ) { SetOpt_( CURLOPT_UPLOAD, post ); const CURLcode res = curl_easy_perform( curl_.get() ); if ( CURLE_OK != res ) throw runtime_error( string( "curl_easy_perform() failed: " ) + curl_easy_strerror( res ) ); const string htmlCopied = html_; html_.clear(); return htmlCopied; } template< typename ParamType > void SetOpt_( CURLoption option, const ParamType ¶meter ) { CURLcode res = curl_easy_setopt( curl_.get(), option, parameter ); if ( CURLE_OK != res ) throw runtime_error( string( "curl_easy_setopt failed: " ) + curl_easy_strerror( res ) ); } static size_t WriteMemoryCallback( void *contents, size_t size, size_t numberOfMemoryBlock, void *userChunk ) { const size_t realSize = size * numberOfMemoryBlock; string &html = *static_cast< string * >( userChunk ); html += string( static_cast< char* >( contents ), realSize ); return realSize; } static size_t ReadDataCallback( char *buf, size_t size, size_t nitems, void *instream ) { string &put = *static_cast< string * >( instream ); const size_t putSize = put.size(); const size_t minSize = min( putSize, size * nitems ); memcpy( buf, put.c_str(), minSize ); if ( minSize == putSize ) put.clear(); else put = put.substr( minSize ); return minSize; } }; |
Once you compile it and run it, you will see something like this result.
pi@desktoppi 01:16:12 hue$ make g++-4.7 -Wall -g -std=c++11 -c stdafx.h g++-4.7 -Wall -g -std=c++11 -lcurl -o hue hue.cpp pi@desktoppi 01:16:35 hue$ ./hue Usage: ./hue light# or ./hue light# key value Example#1: ./hue 1 on true Example#2: ./hue 2 bri 255 Example#3: ./hue 3 hue 65535 pi@desktoppi 01:16:37 hue$ ./hue 2 {"state": {"on":false,"bri":254,"hue":14910,"sat":144,"effect":"none","xy":[0.4596,0.4105],"ct":369,"alert":"none","colormode":"ct","reachable":true}, "type": "Extended color light", "name": "Hue Lamp 2", "modelid": "LCT001", "manufacturername": "Philips","uniqueid":"00:17:88:01:00:b1:6b:b9-0b", "swversion": "66013452", "pointsymbol": { "1":"none", "2":"none", "3":"none", "4":"none", "5":"none", "6":"none", "7":"none", "8":"none" }} pi@desktoppi 01:16:43 hue$ ./hue 2 on true [{"success":{"/lights/2/state/on":true}}] pi@desktoppi 01:16:51 hue$ ./hue 2 on false [{"success":{"/lights/2/state/on":false}}] pi@desktoppi 01:17:01 hue$
No comments:
Post a Comment