ใช้งาน bluetooth บน Raspberry Pi

ติดตั้งแบบ download source code และ compile เอง (ใช้เวลานานมากพอสมควรตอน compile)

อ่านที่ https://learn.adafruit.com/install-bluez-on-the-raspberry-pi/installation

download BlueZ Package http://www.bluez.org/download/

cd ~

wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.45.tar.xz

tar xvf bluez-5.45.tar.xz

cd bluez-5.45

ติดตั้ง Lib ที่เกี่ยวข้อง


sudo apt-get update
sudo apt-get install -y libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev

ทำการ compile


./configure

make

sudo make install

systemctl status bluetooth

sudo systemctl start bluetooth

sudo systemctl stop bluetooth

sudo systemctl enable bluetooth

sudo systemctl disable bluetooth

Enable Bluetooth Low Energy Features


sudo nano /lib/systemd/system/bluetooth.service

Enable the experimental features by adding –experimental to the ExecStart line.

sudo systemctl daemon-reload

sudo systemctl restart bluetooth

อันนี้อีกวิธี แบบไม่ต้อง compile เอง

https://github.com/EnableTech/raspberry-bluetooth-demo
sudo apt-get install pi-bluetooth
sudo apt-get install bluetooth bluez

sudo apt-get install python-bluez

sudo hciconfig hci0 piscan

sudo hciconfig hci0 name 'Device Name' [change your device name to something else you fancy]

sudo python /usr/share/doc/python-bluez/examples/simple/inquiry.py

Running the Bluetooth Server run the rfcomm-server example:

ก่อนใช้คำสั่งนี้ เพื่อ run rfcomm-server
อ่าน https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=133263

run คำสั่ง sudo sdptool add SP แล้วเพิ่ม -C เข้าไปในไฟล์ /etc/systemd/system/dbus-org.bluez.service หลัง ‘bluetoothd’. จากนั้น Reboot. ไม่งั้นมันจะขึ้น error ประมาณนี้

Traceback (most recent call last):
File "/usr/share/doc/python-bluez/examples/simple/rfcomm-server.py", line 20, in <module>
profiles = [ SERIAL_PORT_PROFILE ],
File "/usr/lib/python2.7/dist-packages/bluetooth/bluez.py", line 176, in advertise_service
raise BluetoothError (str (e))
bluetooth.btcommon.BluetoothError: (2, 'No such file or directory')

sudo python /usr/share/doc/python-bluez/examples/simple/rfcomm-server.py

ลอง download โปรแกรม https://play.google.com/store/apps/details?id=es.pymasde.blueterm&hl=en

มาลองส่งข้อมูลจากโทรศัพท์ android ไปยัง raspberry pi ผ่าน bluetooth

เปิดโปรแกรมกด เรียกเมนู เพื่อค้นหาอุปกรณ์ตามที่เราตั้งชื่อ แล้วทำการเชื่อมต่อ ต่อได้ก็ลองพิมพ์ข้อความดูผลที่เกิดขึ้น

อ่านค่า / ส่งค่า netpie ด้วย C, cURL, json-c

การส่งค่า การอ่าน(รับ)ค่า topic หรือตัวแปร ไปยัง netpie ด้วย C โดยใช้ library cURL (ผ่าน REST API) และ json-c (อ่านค่าที่รับจาก netpie ซึ่งเป็น json array)

โครงสร้างของ rest api ปกติที่เราเรียกด้วย curl ก็จะเป็นประมาณนี้

curl -X PUT https://api.netpie.io/topic/ThingsControl/seal/status?retain&auth=แทนค่าด้วย app key:แทนค่าด้วย app secret -d “ON”

https://api.netpie.io/topic/ThingsControl/seal/status?retain&auth=xxxxxxxx:yyyyyy

uri : https://api.netpie.io/topic/

/ThingsControl คือ Application ที่สร้างไว้ใน netpie

/seal/status คือ topic หรือตัวแปร

retain คือการให้คงค่าไว้

auth คือ parameter ที่กำหนดการพิสูจน์ตัวตน (ระบุด้วย app key, app secret)

-d “ON” คือ ค่าที่เราจะส่งไปยังตัวแปร

 

ตัวอย่างที่เขียนด้วย C โดยการใช้ cURL ศึกษาได้จาก https://curl.haxx.se/libcurl/c/example.html และ https://stackoverflow.com/questions/7569826/send-string-in-put-request-with-libcurl stackoverflow ช่วยได้เยอะถ้าหาเจอ ha ha ha 😀

การติดตั้ง cURL บน Raspberry pi

sudo apt-get install libcurl4-openssl-dev

ดูเพิ่มเติมได้ที่นี่ https://bitcontrol.ch/en/2016/02/04/iot-remote-power-switch-part-10/

ตัวอย่าง

/***************************************************************************
 * _ _ ____ _
 * Project ___| | | | _ \| |
 * / __| | | | |_) | |
 * | (__| |_| | _ <| |___
 * \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/
/* <DESC>
 * simple HTTP PUT using the easy interface
 * </DESC>
 */

/*
 Things Control. Control anything you want.
 Copyright (C) 2017 Pornthep Nivatyakul

This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.

ThingsControl Copyright (C) 2017 Pornthep Nivatyakul, kaebmoo@gmail.com, seal@ogonan.com
 This program comes with ABSOLUTELY NO WARRANTY;
 This is free software, and you are welcome to redistribute it
 under certain conditions.




*/

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <stdlib.h>

#include <fcntl.h>
#ifdef WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>




#if LIBCURL_VERSION_NUM < 0x070c03
#error "upgrade your libcurl to no less than 7.12.3"
#endif




int main(void)
{
 CURL *curl;
 CURLcode res;
 typedef struct {
 char *key;
 char *secret;
 char *param;
 char *uri;
 } app_key;

app_key AppKey;

char *key = "app key";
 char *secret = "app secret";
 char *param = "auth=";
 char *netpie = "https://api.netpie.io/topic";
 char *app_id = "/ThingsControl";
 char *id = "/seal";
 char *topic = "/status?retain&";
 /* https://api.netpie.io/topic/ThingsControl/seal/status?retain&auth=xxxxx:yyyy*/

int alloc = 0;

AppKey.key = malloc(strlen(key)+1);
 AppKey.secret = malloc(strlen(secret)+1);
 alloc += strlen(param) + strlen(key) + strlen(":") + strlen(secret);
 alloc++;
 AppKey.param = malloc(alloc);
 AppKey.uri = malloc(strlen(netpie)+strlen(app_id)+strlen(id)+strlen(topic)+strlen(param)+strlen(key)+strlen(":")+strlen(secret)+1);

strcpy(AppKey.key, key);
 strcpy(AppKey.secret, secret);
 strcpy(AppKey.param, param);

/* In windows, this will init the winsock stuff */
 curl_global_init(CURL_GLOBAL_ALL);

/* get a curl handle */
 curl = curl_easy_init();
 if(curl) {
 /* First set the URL that is about to receive our PUT. This URL can
 just as well be a https:// URL if that is what should receive the
 data. */


 /* printf("Parameter %s\n", AppKey.param); */
 AppKey.param = strcat(strcat(strcat(AppKey.param, AppKey.key),":"), AppKey.secret);
 AppKey.uri = strcat(strcat(strcat(strcat(strcat(AppKey.uri,netpie), app_id), id), topic), AppKey.param);
 printf("Parameter %s, \nuri %s\n", AppKey.param, AppKey.uri);

curl_easy_setopt(curl, CURLOPT_URL, AppKey.uri);

/* Now specify the PUT data */

 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "ON");

/* Perform the request, res will get the return code */
 res = curl_easy_perform(curl);
 printf("return code %d\n", res);
 /* Check for errors */
 if(res != CURLE_OK)
 fprintf(stderr, "curl_easy_perform() failed: %s\n",
 curl_easy_strerror(res));

/* always cleanup */
 curl_easy_cleanup(curl);
 }
 curl_global_cleanup();
 free(AppKey.param);
 free(AppKey.key);
 free(AppKey.secret);
 free(AppKey.uri);

return 0;
}

 

ตัวหลักหลักก็อยู่ที่

CURL *curl;

curl = curl_easy_init();

curl_easy_setopt(curl, CURLOPT_URL, AppKey.uri); กำหนด URL

curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, “PUT”); บอกให้ PUT

curl_easy_setopt(curl, CURLOPT_POSTFIELDS, “ON”); ค่าที่จะส่งขึ้นไป

res = curl_easy_perform(curl);

ที่นี้มาถึงตอนอ่านค่า

เวลาที่เรียก GET rest api netpie จะส่งค่าคืนมาเป็น json array หน้าตาประมาณนี้

เรียกผ่าน browser

https://api.netpie.io/topic/ThingsControl/seal/status?auth=xxxx:yyyy

[{“topic”:”/ThingsControl/seal/status”,”payload”:”ON”,”lastUpdated”:1497340128,”retain”:true}]

โดย key “topic” ก็เป็นชื่อ topic ตามที่เราสนใจเรียกอ่าน

“payload” ก็เป็นค่าของ topic หรือค่าของตัวแปร

“lastUpdated” เป็นค่าเวลา (epoch time) ที่ตัวแปรถูกกำหนดค่า เช่น 1497340128 อยากรู้ว่าเป็นเวลาเท่าไหร่ ลองเอาไปแปลงค่าดู https://www.epochconverter.com/ ก็จะได้เท่ากับ

GMT: Tuesday, June 13, 2017 7:48:48 AM
Your time zone: Tuesday, June 13, 2017 2:48:48 PM GMT+07:00

“retain” เป็น Boolean บอกว่าตัวแปรมีการคงค่าไว้หรือไม่

ตัวอย่างการเขียนอ่านค่าด้วย C จะมีสองส่วนคือ ส่วนของ rest api ที่เรียกผ่าน cURL ซึ่งก็เรียกผ่าน url ตามปกติ https://api.netpie.io/topic/ThingsControl/seal/status?auth=xxxx:yyyy แต่จะมีการเรียก callback function เพื่อให้มีการเก็บค่าที่ได้มาจาก server มาเก็บไว้ในตัวแปร chuck.memory ด้วย ซึ่งก็จะได้เป็น string แบบ json array มา

จากนั้นก็เอามา Parse ด้วย library json-c (http://json.org/ ทำไม ใช้ตัวนี้? ค้นหาด้วย google แล้วมันโผล่ขึ้นมา ก็เลยลองลองเล่นดู ถ้าดูใน json.org จะเห็นว่ามี library เยอะมาก ชอบตัวไหน ใช้ตัวไหนก็ตามลำบากครับท่าน ผม งมงม ตัวนี้แล้วใช้งานลองผิดไปหลายตลบแล้วมันได้ก็เลยใช้ใช้ไป)

ตัวอย่างที่ใช้งม

การติดตั้ง json-c https://github.com/json-c/json-c

ตัวช่วยถ้า compile แล้ว error https://stackoverflow.com/questions/480764/linux-error-while-loading-shared-libraries-cannot-open-shared-object-file-no-s

การแปลงเวลาจาก epoch time มาให้อ่านกันรู้เรื่อง ดูตัวอย่างจากนี่ https://www.epochconverter.com/programming/c

การใช้ json-c ก่อนจะนำค่าที่ได้จากการ parse json เขาก็แนะนำว่าควรจะทดสอบ type ก่อน เพื่อป้องกันข้อผิดพลาดของการกำหนดค่าตัวแปร เช่น ดูว่าข้อมูลเป็น string, int, Boolean ฯลฯ คงจะเนื่องจากภาษา C การกำหนดค่าตัวแปร เข้มงวดกว่าภาษาอื่น ถ้าผิดประเภทก็จะ error ได้ แต่ถ้าเรารู้โครงสร้างของข้อมูลที่ได้รับมาอยู่แล้วเราก็สามารถระบุ function ที่จะใช้เรียกอ่านค่าได้เลยไม่ว่าจะ get_string() get_int() อะไรทำนองนั้น

คำสั่ง compile ก็ประมาณนี้ cc getnetpie.c -lcurl -ljson-c -o getnetpie

/***************************************************************************
 * _ _ ____ _
 * Project ___| | | | _ \| |
 * / __| | | | |_) | |
 * | (__| |_| | _ <| |___
 * \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/
/* <DESC>
 * Shows how the write callback function can be used to download data into a
 * chunk of memory instead of storing it in a file.
 * </DESC>
 */
 
 /*
 Things Control. Control anything you want.
 Copyright (C) 2017 Pornthep Nivatyakul

This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.

ThingsControl Copyright (C) 2017 Pornthep Nivatyakul, kaebmoo@gmail.com, seal@ogonan.com
 This program comes with ABSOLUTELY NO WARRANTY;
 This is free software, and you are welcome to redistribute it
 under certain conditions.




*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <curl/curl.h>
#include <json-c/json.h>

struct MemoryStruct {
 char *memory;
 size_t size;
};




void json_parse(json_object * jobj) {
 enum json_type type;
 json_object_object_foreach(jobj, key, val) {
 type = json_object_get_type(val);
 switch (type) {
 case json_type_string: 
 printf("type: json_type_string, ");
 printf("value: %s\n", json_object_get_string(val));
 break;
 case json_type_int: 
 printf("type: json_type_int, ");
 printf("value: %d\n", json_object_get_int(val));
 break;
 }
 }
 
/*
 enum json_type type;
 json_object_object_foreach(jobj, key, val) {
 type = json_object_get_type(val);
 switch (type) {
 case json_type_int: printf("type: json_type_int, ");
 printf("value: %dn", json_object_get_int(val));
 break;
 }
 }
*/
}




static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
 size_t realsize = size * nmemb;
 struct MemoryStruct *mem = (struct MemoryStruct *)userp;

mem->memory = realloc(mem->memory, mem->size + realsize + 1);
 if(mem->memory == NULL) {
 /* out of memory! */
 printf("not enough memory (realloc returned NULL)\n");
 return 0;
 }

memcpy(&(mem->memory[mem->size]), contents, realsize);
 mem->size += realsize;
 mem->memory[mem->size] = 0;

return realsize;
}

int main(void)
{
 CURL *curl_handle;
 CURLcode res;

struct MemoryStruct chunk;
 int array_len, i;




chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
 chunk.size = 0; /* no data at this point */

curl_global_init(CURL_GLOBAL_ALL);

/* init the curl session */
 curl_handle = curl_easy_init();

/* specify URL to get */
 curl_easy_setopt(curl_handle, CURLOPT_URL, "https://api.netpie.io/topic/ThingsControl/seal/status?auth=xxx:yyy");

/* send all data to this function */
 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);

/* we pass our 'chunk' struct to the callback function */
 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);

/* some servers don't like requests that are made without a user-agent
 field, so we provide one */
 curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");

/* get it! */
 res = curl_easy_perform(curl_handle);

/* check for errors */
 if(res != CURLE_OK) {
 fprintf(stderr, "curl_easy_perform() failed: %s\n",
 curl_easy_strerror(res));
 }
 else {
 /*
 * Now, our chunk.memory points to a memory block that is chunk.size
 * bytes big and contains the remote file.
 *
 * Do something nice with it!
 */
 printf("%s\n", chunk.memory);
 printf("%lu bytes retrieved\n", (long)chunk.size);

json_object *jobj;
 json_object *array;
 int stringlen = 0;
 enum json_tokener_error jerr;
 enum json_type jtype;
 struct json_tokener *tok;
 tok = json_tokener_new();
 char *type_str;
 
 time_t now;
 struct tm ts;
 char lastUpdated[80];

do {
 stringlen = strlen(chunk.memory);
 jobj = json_tokener_parse_ex(tok, chunk.memory, stringlen);
 } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue);

if (jerr != json_tokener_success)
 {
 fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr));
 // Handle errors, as appropriate for your application.
 }
 if (tok->char_offset < stringlen) // XXX shouldn't access internal fields
 {
 fprintf(stderr, "Error: tok->char_offset < stringlen");
 // Handle extra characters after parsed object as desired.
 // e.g. issue an error, parse another object from that point, etc...
 }
 jtype = json_object_get_type(jobj);
 switch(jtype) {
 case json_type_null:
 type_str = "NULL";
 break;
 case json_type_boolean:
 type_str = "BOOLEAN";
 break;
 case json_type_double:
 type_str = "DOUBLE";
 break;
 case json_type_int:
 type_str = "INT";
 break;
 case json_type_string:
 type_str = "STRING";
 printf("%s\n", json_object_get_string(jobj));
 break;
 case json_type_object:
 type_str = "OBJECT";
 break;
 case json_type_array:
 type_str = "ARRAY";
 break;
 }
 printf("Type %s\n", type_str);




printf("new_obj.to_string()=%s\n", json_object_to_json_string(jobj));

printf("array length %d\n", json_object_array_length(jobj));
 for (i=0; i < json_object_array_length(jobj); i++) {
 printf("%s\n", json_object_to_json_string(json_object_array_get_idx(jobj, i))); 
 }

array = json_object_object_get(json_object_array_get_idx(jobj,0), "topic");
 printf("payload : %s\n", json_object_to_json_string(array));
 
 array = json_object_object_get(json_object_array_get_idx(jobj,0), "payload");
 printf("payload : %s\n", json_object_to_json_string(array));
 
 array = json_object_object_get(json_object_array_get_idx(jobj,0), "lastUpdated");
 now = json_object_get_int(array);
 ts = *localtime((const time_t *) &now);
 strftime(lastUpdated, sizeof(lastUpdated), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
 printf("payload : %d, %s\n", json_object_get_int(array), lastUpdated);

array = json_object_object_get(json_object_array_get_idx(jobj,0), "retain");
 printf("payload : %d\n", json_object_get_boolean(array));


 /*
 jobj = json_object_object_get(jobj, "payload");
 printf("topic : %s\n", json_object_to_json_string(jobj));
 */

}

/* cleanup curl stuff */
 curl_easy_cleanup(curl_handle);

free(chunk.memory);

/* we're done with libcurl, so clean it up */
 curl_global_cleanup();

return 0;
}

run program ก็จะได้ประมาณนี้

pi@register:~/thingscontrol $ ./getnetpie 
[{"topic":"/ThingsControl/seal/status","payload":"ON","lastUpdated":1497340128,"retain":true}]
94 bytes retrieved
Type ARRAY
new_obj.to_string()=[ { "topic": "\/ThingsControl\/seal\/status", "payload": "ON", "lastUpdated": 1497340128, "retain": true } ]
array length 1
{ "topic": "\/ThingsControl\/seal\/status", "payload": "ON", "lastUpdated": 1497340128, "retain": true }
payload : "\/ThingsControl\/seal\/status"
payload : "ON"
payload : 1497340128, Tue 2017-06-13 14:48:48 +07
payload : 1
pi@register:~/thingscontrol $

ความที่ netpie ส่งมาเป็น array กว่าจะงมหาวิธีแงะได้ ลองอยู่หลายรอบ เพราะตัวอย่างที่ค้นเจอ มันมักจะ Parse json แบบ { “topic”:”value”, “status”,”ON” } อะไรงี้ แถม array ไม่มีชื่อ object แบบในตัวอย่างอีก โห กูเหนื่อย 😉 เริ่มมา ปิ๊ง ปิ๊ง หลังจากเจออันนี้ https://stackoverflow.com/questions/10164741/get-jsonarray-without-array-name  และนี่ http://www.jsontest.com/#validate ก็เลยรอดมาได้

เริ่มจากไม่รู้เรื่องเลยก็ใช้เวลาประมาณ 2 วัน 🙂 วันแรกก็ งมการใช้ cURL วันที่สองก็งม parse json หวังว่าท่านจะต่อยอดไปได้เร็วขึ้น

ทำไม ไม่ใช้ python, JavaScript?

อันนั้นมันมีตัวอย่างเยอะละ ที่สำคัญคือ กูเขียนไม่เป็น ha ha ผมมันคนโบราณ ใช้ C แบบถึกถึก นี่แหละ

ปล. code ตัวอย่าง จะมีที่ไม่เกี่ยวข้องอยู่พอสมควร ซึ่งผมใช้ในการ debug ตัว program และเป็นตัวอย่างการใช้งานต่าง ๆ

 

 

อ่านค่า (topic) จาก netpie ด้วย PHP rest api

จาก

อันดับแรกไป download httpful มาจากนี่ http://phphttpclient.com/downloads/httpful.phar

ถ้ายังไม่มี lib curl สำหรับ php ต้องติดตั้งก่อน (ดูตัวอย่าง https://stackoverflow.com/questions/6382539/call-to-undefined-function-curl-init)

sudo apt-get install php5-curl

ลองส่งข้อมูลขึ้นไปบน netpie (ถ้ายังไม่มี curl ก็ติดตั้งก่อน)

curl -X PUT "https://api.netpie.io/topic/APPID/TOPIC/debug?retain&auth=KEY:SECRET" -d ":-)"

โดยแทนค่า APPID ด้วยชื่อ APP ของเราที่สร้างใน netpie
แทนค่า TOPIC ด้วยชื่อที่ต้องการ เช่น Room
แทนค่า KEY ด้วยค่า key ที่อยู่ใน APP ที่สร้างขึ้นใน netpie
แทนค่า SECRET ด้วยค่า secret ที่อยู่ใน APP ที่สร้างขึ้นใน netpie

ถ้ายังไม่มีก็ไปสมัครใช้งานก่อนที่ netpie.io

debug ก็เป็น topic หรือตัวแปรตัวหนึ่ง ในที่นี้เรากำหนดค่าให้มัน เท่ากับ “:-)” ด้วยคำสัั่ง -d “:-)”

retain คือการให้ netpie รับข้อมูลไปแล้วคงค่าไว้

auth= คือ parameter ที่จะต้องส่งไปให้ netpie ตรวจสอบยืนยันตัวตนด้วยค่า key และ secret

<!--?php 

        include "httpful.phar";
        // กำหนด uri
        $uri = "https://api.netpie.io/topic/APPID/TOPIC/debug?auth=KEY:SECRET";
        
        // สั่งให้เรียก uri โดยใช้คำสั่ง GET เพื่อขออ่านค่าจาก netpie
        $response = \Httpful\Request::get($uri)->send();
        
        // แปลงค่าที่ได้จาก netpie จาก json มาเป็น array
        $result = json_decode($response->body, true);

        // ลองพิมพ์ค่าที่ได้ออกมาดู 
        // netpie จะเก็บค่าของตัวแปรไว้ใน json ที่ชื่อ payload
        echo "debug = " . $result[0]['payload'] . "\n";
        $debug = $result[0]['payload'];
        
        echo $response . "\n" ;
        sleep(1);
?-->

ถ้าต้องการอ่านค่าอื่น ก็ทำซ้ำใหม่ตั้งแต่การกำหนด uri โดยแค่เปลี่ยนจากตัวแปร debug ไปเป็นอื่น ๆ เช่น switch, pump เป็นต้น

$uri = "https://api.netpie.io/topic/APPID/TOPIC/switch?auth=KEY:SECRET";

อย่าลืมลองส่งค่าขึ้นไปก่อน

curl -X PUT "https://api.netpie.io/topic/APPID/TOPIC/switch?retain&auth=KEY:SECRET" -d "ON"

ระหว่างการ อ่านค่าตัวแปรแต่ละครั้งควรมีการตั้งค่าเวลาระหว่างการอ่านอย่างน้อย 1 วินาทีด้วยคำสั่ง sleep(1) (ตามข้อกำหนด) ถ้าไม่จำเป็นต้องอ่านค่าแบบทันทีทันใดก็ตั้งให้นานกว่านั้นได้ เพราะบางครั้งถ้าระบบบริการของ netpie มีปริมาณการส่งข้อมูลมากมาก อาจเกิดการล่าช้าในการปรับปรุงค่าตัวแปรได้ ทำให้การอ่านค่าบางครั้งจะไม่ได้ค่าที่เป็นปัจจุบันเนื่องจากระบบอยู่ระหว่างการประมวลผล

ตัวอย่างผลลัพธ์

pi@register:/var/www/html $ php read.netpie.data.php 
HH = 06
[{"topic":"/ThingsControl/seal/HH","payload":"06","lastUpdated":1496741674,"retain":true}]
MM = 30
[{"topic":"/ThingsControl/seal/MM","payload":"30","lastUpdated":1496741674,"retain":true}]
Enable = true
[{"topic":"/ThingsControl/seal/Enable","payload":"true","lastUpdated":1496740819,"retain":true}]
On Timer = 20
[{"topic":"/ThingsControl/seal/OnTimer","payload":"20","lastUpdated":1496741673,"retain":true}]
Sun = false
[{"topic":"/ThingsControl/seal/Sun","payload":"false","lastUpdated":1496740819,"retain":true}]
Mon = 1
[{"topic":"/ThingsControl/seal/Mon","payload":"1","lastUpdated":1496741676,"retain":true}]
Tue = false
[{"topic":"/ThingsControl/seal/Tue","payload":"false","lastUpdated":1496741676,"retain":true}]
Wed = 3
[{"topic":"/ThingsControl/seal/Wed","payload":"3","lastUpdated":1496741670,"retain":true}]
Thu = false
[{"topic":"/ThingsControl/seal/Thu","payload":"false","lastUpdated":1496740808,"retain":true}]
Fri = 5
[{"topic":"/ThingsControl/seal/Fri","payload":"5","lastUpdated":1496741667,"retain":true}]
Sat = false
[{"topic":"/ThingsControl/seal/Sat","payload":"false","lastUpdated":1496741668,"retain":true}]
pi@register:/var/www/html $

*** ทดสอบการใช้งานบน raspberry pi 3

แถมตัวอย่างเขียนด้วย Python (อย่าลืมแทนค่า KEY และ SECRET ในตัวอย่าง ด้วยค่าที่ได้จาก netpie) พึ่งหัดเขียน python วันแรก เอาแค่นี้ไปก่อน 😛 ไว้ใช้เป็นเมื่อไหร่จะมาเขียนต่อ   ตัวอย่างใน web ก็มีหลายอันอยู่ เช่น http://raspberrypi-thailand.blogspot.com/2016/07/raspiberry-pi-netpie.html

import microgear.client as client
import logging
import time

appid = "ThingsControl"
gearkey = "KEY"
gearsecret = "SECRET"

client.create(gearkey,gearsecret,appid,{'debugmode': True})

def connection():
    #print "Now I am connected with netpie"
    logging.debug("Now I am connected with netpie")

def subscription(topic,message):
    #print topic + " " + message
    logging.debug(topic + " " + message)

def disconnect():
    logging.debug("disconnected")

client.setalias("ThingsControl")
client.on_connect = connection
client.on_message = subscription
client.on_disconnect = disconnect
client.subscribe("/seal/Sun")
time.sleep(1)
client.subscribe("/seal/Sat")
time.sleep(1)

client.subscribe("/seal/HH")
time.sleep(1)

client.subscribe("/seal/MM")

client.connect()

จบ

Register System by WIFI

ระบบลงทะเบียน ระบบ check-in ระบบลงเวลา ระบบกรอกแบบสอบถาม หรืออื่น ๆ ผ่านระบบ wifi

ทำไมต้องใช้ระบบนี้? เหตุผลที่จัดทำระบบนี้ก็คือการลงทะเบียนออนไลน์ ที่ต้องการให้ผู้ลงทะเบียนอยู่ในพื้นที่หรือสถานที่ ที่กำหนดเท่านั้นที่จะสามารถกรอกข้อมูลได้ เพราะจุดอ่อนของระบบออนไลน์ทั่วไปผู้ใช้งานสามารถเชื่อมต่อเข้า Internet ก็จะสามารถเข้าถึงระบบจากที่ไหนก็ได้ จึงเป็นข้อกังวลของการตรวจสอบได้ ทางออกของการแก้ไขปัญหานี้สามารถทำได้หลายวิธี เช่น การตรวจสอบตำแหน่งผ่านระบบ GPS หรือ Geo-location ซึ่งเราสามารถเขียน web application เพื่อตรวจสอบตำแหน่งของผู้ใช้ ว่าอยู่ในพื้นที่ ที่เรากำหนดไว้หรือไม่ แต่การใช้วิธีดังกล่าวก็ต้องเขียน software เพิ่มเติมซึ่งก็มีความยุ่งยากในการทำพอสมควร อีกวิธีที่ง่ายกว่าก็คือการทำระบบให้สามารถเข้าถึงได้ผ่าน wifi ที่กำหนด ซึ่งด้วยรัศมีของ wifi ที่ไม่ไกลมากนัก ระยะใช้งานได้อยู่ที่ประมาณ 50-70 เมตร ซึ่งก็จะสามารถใช้จำกัดพื้นที่ ว่าผู้ที่จะใช้งานระบบลงทะเบียนจะต้องอยู่ในพื้นที่รัศมีของสัญญาณ wifi ที่กำหนด ซึ่งก็จะเป็นการแก้ปัญหาการตรวจสอบตำแหน่งได้แบบหนึ่ง ในวิธีแบบนี้จำเป็นต้องใช้ hardware เข้ามาช่วย (ถ้าไม่ใช้ harware ก็ต้องใช้การเขียน software แบบวิธีแรก) ซึ่ง hardware นี้เราสามารถใช้อุปกรณ์เช่น raspberry pi มาทำได้ด้วยต้นทุนประมาณ สองพันบาทนิดนิดก็สามารถทำได้แล้ว หรือถ้าเป็นระบบที่ไม่ต้องการความยืดหยุ่นมาก เป็นระบบที่จำเพาะเจาะจงก็สามารถใช้อุปกรณ์ micro controller อื่นมาใช้งานก็ได้เหมือนกันเช่น บอร์ด ESP32, ESP8266 เป็นต้น แต่อาจจะมีความยุ่งยากมากกว่าเพราะระบบนี้ต้องการการเชื่อมต่อกับเครือข่ายอินเทอร์เน็ตด้วย

ระบบนี้ทำงานอย่างไร

ให้เรากำหนดชื่อสำหรับการเชื่อมต่อ wifi (SSID) เพื่อแจ้งให้ผู้ใช้งานทราบว่าจะต้องเชื่อมต่อกับ wifi ไหน เช่น Register-Wifi เป็นต้น

สำหรับตัวระบบ เราสามารถใช้หลักการดักจับได้หลายแบบ เช่น การใช้หลักการของ captive portal หรือ DNS อย่างใดอย่างหนึ่งหรือทั้งสองก็ได้ ในกรณีที่ใช้ DNS เราสามารถระบุชื่อ Host หรือ domain ที่เราตั้งขึ้นมาเอง และแจ้งผู้ใช้ทราบว่าจะต้องเข้า url อะไรในการลงทะเบียน เช่น http://register.event เป็นต้น

เมื่อผู้ใช้ระบุ url ดังกล่าวใน browser ระบบก็จะ redirect ไปยัง web server ที่สร้างขึ้นไว้ในตัวระบบเองหรือไปยัง web server ตัวอื่นก็ได้ โดยที่ web server ดังกล่าว ก็จะทำหน้าสำหรับกรอกข้อมูลหรือใส่เงื่อนไขต่าง ๆ ตามที่เราต้องการได้ เช่น การกำหนดเวลาให้ลงทะเบียนได้เฉพาะช่วงเวลาใดเวลาหนึ่ง เป็นต้น ทั้งนี้ระบบที่อยู่ที่ web server ก็สามารถเขียนโปรแกรมเพื่อทำงานตามเงื่อนไขการใช้งานได้อย่างอิสระด้วยภาษาคอมพิวเตอร์ หรือ ไม่ว่าจะเป็นการเชื่อมต่อกับระบบฐานข้อมูล หรือเชื่อมกับระบบงานอื่นที่จำเป็น อาจจะมีประเด็นเพิ่มเติมว่าถ้าผู้ใช้งานทราบ url สุดท้ายหลังจากที่ มีการ redirect จากระบบลงทะเบียนไปแล้ว เช่น ถ้าเราใช้ google form ในการเก็บข้อมูล ผู้ใช้จะเห็น url ของ form ดังกล่าว และสามารถผ่านเข้าไปใช้งานได้โดยตรงโดยไม่ผ่านระบบลงทะเบียนนั้น การแก้ไขก็สามารถทำได้ด้วยการทำระบบกรอกข้อมูลขึ้นเองและทำอยู่ภายในระบบ Register นี้หรือทำบนระบบ Server ที่จะต้องต้องอาศัยการทำ VPN เข้าไปเท่านั้น โดยกำหนดให้มีการทำ VPN ระหว่าง ระบบ register นี้กับ Server ก็จะสามารถป้องกันไม่ใช้ผู้ใช้งานเข้าถึงระบบกรอกข้อมูลได้โดยตรง

ดูตัวอย่างแผนภาพการทำงาน

register_system

ตัวอย่างการเขียน code ด้วย php เพื่อตรวจสอบช่วงเวลาและส่งค่า url ตามที่กำหนด

<?php
$local_time = date(‘YmdHis’);
$start_morning_time = ‘20170520080000’;
$end_morning_time = ‘20170520081500’;
$start_afternoon_time = ‘20170520130000’;
$end_afternoon_time = ‘20170520131500’;

if ($local_time >= $start_morning_time && $local_time <= end_morning_time) {
header(“Location: https://goo.gl/forms/OWD7oeb8Uh7oYa9m2&#8221;);
}
else if ($local_time >= $start_afternoon_time && $local_time <= end_afternoon_time) {
header(“Location: https://goo.gl/forms/D9eTTUpHIXbTGpKp1&#8221;);
}
else {
header(“Location: https://catevent.dyndns.info/event/seminar-finance2017&#8221;);
}
?>

ตัวอย่างของการใช้ nginx และให้มีการ redirect ไปยัง url ที่กำหนด

# Default server configuration
#
server {
listen 80 default_server;
listen [::]:80 default_server;

server_name register;
rewrite ^/$ http://register.event/index.php redirect;

.

.

}

ตัวอย่างการใช้ dnsmasq ในการกำหนดชื่อ dns หรือ host ที่ให้ผู้ใช้ระบุเพื่อเข้าระบบลงทะเบียนโดยมีการส่งต่อไปยังเครื่องที่กำหนด (เช่น web server) – /etc/dnsmasq.conf

interface=eth0 # Use interface eth0 wlan0
listen-address=172.24.1.1 # Explicitly specify the address to listen on
bind-interfaces # Bind to the interface to make sure we aren’t sending things elsewhere
server=8.8.8.8 # Forward DNS requests to Google DNS
domain-needed # Don’t forward short names
bogus-priv # Never forward addresses in the non-routed address spaces.
dhcp-range=172.24.1.10,172.24.1.250,1h # Assign IP addresses between 172.24.1.10 and 172.24.1.250 with a 12 hour lease time

address=/register.event/www.finance.register/finance.register/register/172.24.1.1

 

 

How to run shell_exec command in php

https://unix.stackexchange.com/questions/115054/php-shell-exec-permission-on-linux-ubuntu

The Apache’s user www-data need to be granted privileges to execute certain applications using sudo.

  1. Run the command sudo visudo. Actually we want to edit the file in etc/sudoers.To do that, by using sudo visudo in terminal ,it duplicate(temp) sudoers file to edit.
  2. At the end of the file, add the following ex:-if we want to use command for restart smokeping and php command for another action in your question,

www-data ALL=NOPASSWD: /etc/init.d/smokeping/restart, usr/bin/php

(This is assuming that you wish to run restart and php commands using super user (root) privileges.And you use php command in usr/bin/ path )

However, if you wish to run every application using super user privileges, then add the following instead of what’s above.You might not want to do that, not for ALL commands, very dangerous.

www-data ALL=NOPASSWD: ALL

3.After edit the sudoers file(by visudo we edit the temp file of sudoers so save and quit temp file(visudo) to write in sudoers file.(wq!)

4.That’s it, now use exec() or shell_exec in the following manner inside your xxx.phpscript.keep remember to use sudo before the command use in the php script.

ex:-

exec ("sudo /etc/init.d/smokeping restart 2>&1");

or

shell_exec("sudo php -v"); 

So in your problem,add the commands that you wish to use in to the step no (2.) as I add and change your php script as what you want.

here is the same problem as yours http://stackoverflow.com/a/22953339/1862107

ติดตั้ง webmin บน Raspberry Pi

Download ตัวโปรแกรมติดตั้ง

wget http://prdownloads.sourceforge.net/webadmin/webmin_1.831_all.deb

ติดตั้ง library และโปรแกรมที่เกี่ยวข้อง

sudo apt-get install  libnet-ssleay-perl libauthen-pam-perl  libio-pty-perl  apt-show-versions  libapt-pkg-perl

หรือ sudo apt-get install perl libnet-ssleay-perl openssl libauthen-pam-perl libpam-runtime libio-pty-perl apt-show-versions python

ติดตั้ง webmin

sudo dpkg --install webmin_1.831_all.deb

Login เข้า webmin ด้วยคำสั่ง https://ชื่อเครื่องหรือไอพี:10000

ใส่ user: pi และรหัสผ่าน

 

 

การใช้คำสั่ง shell_exec ใน php

การใช้คำสั่ง shell_exec ใน php เช่น

$output = shell_exec('sudo /home/seal/bin/reload_iperf.sh');

การใช้คำสั่ง shell_exec ใน php ที่ทำงานบน web server นั้น จำเป็นต้องมีการตั้งค่าสิทธิอนุญาตการทำงานก่อน เพื่อให้คำสั่งดังกล่าวนั้นสามารถทำงานได้ การกำหนดสิทธินั้นทำได้ด้วยการระบุ ในไฟล์ /etc/sudoers ซึ่งสามารถแก้ไขได้ด้วยคำสั่ง sudo visudo

แล้วเพิ่ม โดย www-data คือ user ที่ใช้ run โปรแกรม web

www-data ALL=NOPASSWD: /home/seal/bin/reload_iperf.sh

เข้าไปในไฟล์ดังกล่าว

รายละเอียดเพิ่มเติมอ่านได้จาก http://unix.stackexchange.com/questions/115054/php-shell-exec-permission-on-linux-ubuntu