วันอาทิตย์ที่ 20 กันยายน พ.ศ. 2558

Node-RED : ใช้งาน MQTT ด้วย Arduino

 

บทความที่แล้วกล่าวถึงการสมัครใช้งาน MQTT Broker กับ CloudMQTT ตอนนี้หลายคนคงมี user และ password แล้วก็ใช้งานกันบ้างแล้ว

MQTT จะกล่าวถึง Publish เป็นการฝากข้อมูลไว้ด้วยการตั้งชื่อ topic และ Subscribe คือการสมัครเพื่อรับข้อมูลกับ broker โดยที่ broker จะจัดส่ง topic ที่สมัครไว้ ที่มีข้อมูลใหม่ๆ ให้กับผู้ที่ได้ทำการสมัครรับข้อมูล topic นั้นๆไว้ ด้านผู้ที่สมัครต้องเตรียมการในการรับข้อมูลที่ broker จัดส่งให้ โดยเรียกการเตรียมการว่าเป็นการรอรับ callback การทำงานจะใช้หลักการของ Event driven

สิ่งที่เกริ่นมาจะเป็นหลักการในการเขียนโปรแกรมเพื่อรองรับการทำงาน แต่โชคดีจริงๆที่มีคนที่ไม่นิ่งดูดาย ได้จัดทำไลบรารี่สำหรับการนี้มาให้เราใช้เรียบร้อยแล้วในชื่อ Arduino Client for MQTT

บทความนี้จะนำสิ่งที่ต้องปรับแก้ในตัวอย่างที่ให้มาในไลบรารี่ เพื่อให้ทำงานได้ถูกต้อง

ก่อนอื่นเราต้องนำเอาไลบรารี่มาวางในโฟลเดอร์ libraries ของ Arduino 1.6.5r2 เสียก่อน

https://github.com/knolleary/pubsubclient

เข้าไปรับไฟล์ zip มาติดตั้งเสียให้เรียบร้อย

image

ขอนำเอาหน้าตาคนเขียนไลบรารี่มาให้ดูกัน งานนี้ไม่ได้ขออนุญาตโดยตรงกับเจ้าของผลงาน เพราะอยู่ในเงื่อนไขของ MIT License. อยู่แล้ว สามารถนำผลงานไปเผยแพร่ได้

วางไลบรารี่เรียบร้อย ดำเนินการเปิด Arduino 1.6.2r5 จากนั้นเรียกตัวอย่างมาทดลองกันเลย ให้เลือก mqtt_esp8266 ซึ่งอยู่ใน PubSubClient

เริ่มการตั้งค่ากันก่อน

const char* ssid = "........";
const char* password = "........";
const char* mqtt_server = "broker.mqtt-dashboard.com";

ssid กับ password คงคุ้นกันอยู่แล้ว ส่วน mqtt_server ก็นำมาจากที่เราสมัครไว้กับ CloudMQTT ตัวอย่างของผมคือ m11.cloudmqtt.com ย้อนไปอ่านในบล๊อกที่แล้วครับ

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

ตัวเลข 1883 เป็นหมายเลข port ดูจากที่สมัครไว้ ตัวอย่างที่ผมได้รับจาก CloudMQTT เป็น 15749

สำหรับ BUILTIN_LED เป็น pin ของ ESP8266 โดยถูกกำหนดค่าไว้ที่ 16 ที่ pin ของ ESP8266 ให้ต่อ LED ไว้ดวงหนึ่ง เพื่อทดสอบการรับ callback จาก broker

ส่วนบรรทัดสุดท้ายจะบอกตำแหน่งรูทีนที่จะให้ทำงานเมื่อได้รับ callback จาก broker ในที่นี้กำหนดให้ไปทำที่ รูทีน callback ตามที่แสดงด้านล่าง

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is acive low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

}
รูทีน callback จะมีตัวแปร topic, payload และ length มารอรับข้อมูลที่ broker ส่งมา ในรูทีนจะแสดง topic ที่รับมา โดยที่ข้อมูลหรือ message จะอยู่ใน payload โดยนำมาแสดงบน serial monitor

อีกส่วนคือการนำ message ที่ส่งมา นำมาเปิด ปิด LED โดยจะดูว่าตัวอักษรตัวแรกเป็น 0 ก็จะให้ LED ติด และถ้าเป็น 1 ก็จะดับหลอด LED

อีกส่วนที่สำคัญคือ รูทีน reconnect() ส่วนที่เป็นสีแดง ต้องทำการแก้ไข เนื่องจากจำเป็นต้องระบุ user และ password ให้กับ CloudMQTT

if(client.connect(“ESP8266Client”,”user”,”password”)) {

user และ password กำหนดให้โดย CloudMQTT เช่นกัน

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
   if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

สำหรับการ publish ได้ตั้งชื่อ topic ว่า outTopic และส่งค่า hello world ออกไป

client.publish(“outTopic”,”hello world”);

ส่วนการ subscribe จะรอรับ callback จาก topic ชื่อ inTopic

client.subscribe(“inTopic”);

โค๊ดส่วนอื่นๆก็เป็นการเตรียมเรื่อง WiFi และการคงการเชื่อมต่อให้ได้ตลอดเวลา

ส่วนการทำงานวนลูป จะทำการ publish topic ชื่อ outTopic ออกไปเป็นจังหวะห่างกันครั้งละประมาณ 2 วินาที

ทำการคอมไพล์และอัพโหลด ถ้าทุกสิ่งทำงานจะเห็นข้อมูลใน Serial monitor ลักษณะนี้ ต่อจากการเชื่อมต่อกับ WiFi โดยตัวเลขต่อท้าย hello world จะเพิ่มขึ้นเรื่อยๆ

Attempting MQTT connection...connected
Publish message: hello world #1
Publish message: hello world #2
Publish message: hello world #3
Publish message: hello world #4
Publish message: hello world #5
Publish message: hello world #6

การทดสอบการทำงาน

ให้เปิด Websocket UI ของ CloudMQTT (ดูวิธีในบล๊อกล่าสุด)

image

ทันทีที่เปิดก็จะเห็น Received message ตามภาพ ซึ่งก็คือการ publish โดย ESP8266 ด้วย topic outTopic

ทดลอง Send message (เป็นการ publish topic ชื่อ inTopic) ป้อน message เป็นตัวอักษรหรือข้อความก็ได้ สังเกตุผลที่ Serial monitor

ได้ทดลองส่งคำว่า Hi ออกไป ที่ Serial monitor ก็แสดงคำดังกล่าวทันที

Publish message: hello world #1281
Publish message: hello world #1282
Publish message: hello world #1283
Publish message: hello world #1284
Message arrived [inTopic] Hi

ทดลองส่ง message 0 หรือ 1 ซึ่งจะเห็น LED ติดและดับ ตามลำดับ

จะเห็นว่าการทำ publish และ subscribe เป็นแบบตรงไปตรงมา ไม่มีความยุ่งยาก ตัวอย่างที่ได้เห็นน่าจะทำให้เข้าใจการทำงานของ MQTT Broker ได้ชัดเจนยิ่งขึ้น

ผู้อ่านอาจประยุกต์ให้ publish ข้อมูลอุณหภูมิ และ subscribe เพื่อรับ callback มาเปิด ปิด หลอดไฟ หรือ subscribe ค่า analog มาทำการหรี่ไฟ

ผมแนะนำให้นำผลที่ได้จากบทความไปทดลองเขียน flow ใน NodeRED เพื่อขยายผลการประยุกต์การใช้งาน

ในส่วนของการทดสอบ MQTT มี app ใน Playstore ชื่อ MyMQTT สามารถใช้ทดสอบการทำงานแทน Websocket ของ CloudMQTT ได้เป็นอย่างดี ลองโหลดมาทดลองใช้ดูครับ

วันศุกร์ที่ 18 กันยายน พ.ศ. 2558

Node-RED : MQTT ตามที่ผมเข้าใจ

 

MQTT (Message Queuing Telemetry Protocol)

ผมได้เขียนเนื้อหาเกี่ยวกับการฝากและดึงข้อมูล เพื่อทำให้ Iot devices สามารถทำงานได้โดยอิสระจากการที่จะต้องผูกติดกับ PC ที่บ้าน ทำให้การรีโมทมาที่ devices สามารถกระทำได้ทุกที่ที่ต้องการ ถ้ายังจำได้ผมได้ใช้ dweet.io เป็นที่ฝากข้อมูล และ Phant ทำหน้าที่เดียวกันแต่เป็นแบบ inhouse

สำหรับ MQTT เป็นชื่อเรียกโปรโตคอล มาตรฐานในการฝากและดึงข้อมูลคล้ายกับ Dweet.io และ Phant ส่วนของ MQTT เป็นมาตรฐานที่ IBM เป็นผู้ริเริ่ม (ผมขอไม่พูดถึงประวัติความเป็นมา ไม่ถนัดที่จะเล่าเรื่องที่มาที่ไปนัก) เพื่อควบคุมระบบสัญญานและข้อมูลในโรงงานอุตสาหกรรม ซึ่งเกิดขึ้นก่อน IoT นานพอควร แต่ด้วยสอดคล้องกับ IoT จึงได้รับความนิยม

Dweet.io เป็น MQTT broker แบบ lite คือ นำเอาเฉพาะส่วนสำคัญมาใช้ สุดๆก็คือ Dweet.io ที่แทบจะไม่ต้องทำอะไรเลย คือไม่ต้องสมัคร เพียงวางรูปแบบให้ถูกต้องตามที่กำหนด ก็สามารถทำงานได้แล้ว

ในส่วนของ Phant จะเต็มรูปแบบที่เราสามารถนำมาติดตั้งไว้ในเครื่องของเราได้ ก็คือไม่ต้องไปเสียเงินซื้อแพ็คเกจ

ความเห็นส่วนตัวผมชอบที่จะใช้บริการมากกว่าจะมาวางไว้ในเครื่อง ซึ่งเราต้องคอยดูแลให้มันทำงานได้ตลอดเวลา ซึ่งจุดนี้ควรจะให้ผู้เชี่ยวชาญดูแลให้เราดีกว่า

MQTT จะใช้หลักการของการ dispatch ข้อมูลที่มีการเปลี่ยนแปลงออกไป ในส่วนของผู้ใช้งานก็จะเขียนโปรแกรมในลักษณะรอรับข้อมูล event driven หรือ Asynchronous หลักการก็คือ ทำการระบุเหตุการณ์หรือ event ให้หน่วยบริการหรือ handler คอยเฝ้าดูแทนเรา เมื่อใดที่พบเห็นเหตุการณ์ที่ระบุไว้ ให้แจ้ง เมื่อได้รับแจ้ง CPU จะละงานที่กำลังทำอยู่ ไปทำงานในรูทีนที่กำหนด

ดังนั้น CPU ไม่ต้องทำการหยุดรอข้อมูล หรือต้องเข้ามาดึงข้อมูลตามที่ตั้งเวลาแน่นอนไว้ ทั้งที่อาจจะไม่ได้มีข้อมูลใหม่เข้ามา เมื่อฝากเรื่องไว้กับ handler แล้ว CPU สามารถไปทำงานอื่นๆได้โดยอิสระ

ข้อมูลที่ได้รับจะเป็นข้อมูลที่ทันสมัยตลอดเวลา CPU ทำงานได้เต็มประสิทธิภาพ การเขียนโปรแกรมแบบ event driven หรือ Asynchronous ง่ายกว่าแบบ polling มากๆ

จากที่ได้ติดตามเห็นการทดลองของเพื่อนๆในกลุ่มที่ได้ทดลองกับ ESP8266 โดยการใช้ HTTP client ที่เป็นรูปแบบของการเขียนโปรแกรมในลักษณะ polling คือวนลูปเพื่อตรวจสอบว่ามีการร้องขอข้อมูลหรือไม่ เมื่อเปรียบเทียบกับการเขียนโปรแกรมแบบ HTTP server ที่จะตอบสนองเมื่อเกิด event หรือเหตุการณ์ที่พ้องกับที่เรากำหนดไว้ จะมีประสิทธภาพสูงกว่า

ตัวอย่างการเขียนโปรแกรมแบบ HTTP server ผมได้เขียนไว้ในหัวข้อ ESP8266 กับ Webconfig คำสำคัญที่ใช้คือ server.on(“event”, subroutine);

สำหรับเนื้อหาตอนนี้จะนำเอาวิธีใช้งาน MQTT Broker กับ NodeRED

สำหรับ NodeRED มี MQTT node ทั้งแบบ in และ out สำหรับส่วนของจุดบริการฝากข้อมูล ซึ่งถูกเรียกว่า MQTT Broker มีแบบที่ให้ใช่ฟรีโดยมีข้อจำกัด ถ้ายอมเสียเงินก็จะมีอะไรให้ใช้เพิมขึ้น

ผมทดลองสมัครใช้งานแบบฟรีกับ CloudMQTT ใช้ Cute Cat package

image

จะถูกจำกัดที่ 10 connections และความเร็วในการถ่ายโอนอยู่ที่ 10Kbit/s ถ้าใช้แล้วติดใจ ก็ควรสนับสนุนไปใช้ package ที่สูงขึ้นได้ตามความเหมาะสม

ส่วนของจ้าวอื่นยังไม่ได้ค้นหา ใครพบว่ามีที่ไหนบ้าง ก็นำไปโพสต์ไว้ในเฟส NodeRED Siam ได้ครับ จะได้แชร์ให้เพื่อนๆ

 

image

สมัครกันเลย เข้าที่ https://www.cloudmqtt.com/ เลือก Plan เลือก Cute Cat กรอกรายละเอียด รอ email เพื่อ confirm จากนั้นก็ทำการ Log-In

image

กดที่ + Create

image

ตั้งชื่อ เลือก Data center และแน่นอน Plan ให้เลือก Cute Cat ทำการ Save

เมื่อกลับไปที่หน้า CloudMQTT Instances ให้กดปุ่ม Details

image

จะพบกับข้อมูลสำคัญที่ต้องนำไปใช้กับ NodeRED คือ Server, User, Password และ Port สังเกตุุค่า Connection limit อยู่ที่ 10 ผมยังไม่ชัดเจนนักกับคำว่า connections ว่าหมายถึงอะไร

ก่อนจะไปที่ NodeRED มาทดลองใช้งานเครื่องมือที่ CloudMQTT ให้มาก่อน

image

* ในรูปผมจะลบชื่อ User ที่ต่อท้ายคำว่า Console ออก  ส่วนของผู้อ่านเองจะเห็น User ที่ระบบกำหนดแสดงไว้ที่ตำแหน่งนั้น

จากนั้นให้กดปุ่ม Webservice UI

image

Websocket ที่กำลังจะใช้เพื่อการทดสอบการฝากและดึงข้อมูล มีการแบ่งเป็นส่วน Send message และ Received messages

ในภาพจะเห็นข้อมูลในส่วน Received messages ที่ส่งมาจาก FRED (NodeRED แบบ online ยังจำกันได้หรือป่าว) ขณะที่เขียนผมไม่ได้เปิดใช้งาน FRED แต่ flow ที่ได้เขียนไว้ยังทำงานอยู่ตลอดเวลา เป็นการยืนยันว่า flow ที่ active อยู่จะทหน้าที่ของมัน แม้ว่าเราจะปิด browser ไปแล้ว

ตอนนี้ให้ทดลองใส่ข้อมูลใน Topic ซึ่งสามารถจัดกลุ่มของข้อมูลได้ด้วย สำหรับตัวอย่างที่เห็นในด้าน Received messages จะมีกลุ่ม livingroom ที่ประกอบด้วย temperature และ humidity เป็นสมาชิก ซึ่งจะเป็นข้อมูลแต่ละตัว เครื่องหมาย / จะคั่นระหว่างกลุ่มกับตัวข้อมูล

ทดลองพิมพ์ livingroom/temperature ในช่อง Topic และ 25 ในช่อง Message และ กดปุ่ม Send

image

* ในภาพผมได้ทำให้ flow ที่ active อยู่ หยุดทำงาน และ refresh browser จะเห็นด้าน Received messages จะถูกเคลียร์

จะเห็นข้อมูลเดียวกันที่ฝั่ง Received messages แทบจะทันที่ นั่นก็คือ handler แจ้ง CPU ว่ามีข้อมูลใหม่เข้ามา CPU ดำเนินการอ่านข้อมูลและนำค่าที่ได้มาแสดง

ด้าน Received messsages จะแสดงข้อมูลทั้งหมดที่มีการส่ง

สำหรับการเลือกอ่านข้อมูล จะมีรูปแบบที่ใช้เครื่องหมาย # เป็น wildcard คืออะไรก็ได้ ตัวอย่างเช่น ถ้าเราตั้งกลุ่ม livingroom และมีสมาชิกเป็น temperature และ humidity

ถ้าต้องการรับค่าเฉพาะสมาชิก ให้เขียนรูปแบบ

livingroom/temperature หรือ livingroom/humidity

แต่ถ้าจะรับค่าได้กับสมาชิกทุกตัว ก็ให้เขียนรูปแบบ

livingroom/#

แต่ต้องทำโปรแกรมเพื่อแยกข้อมูลเอง

 

ถีงตอนนำเอาทุกอย่างมารวมกัน ให้เข้าใช้งาน https://fred.sensetecnic.com/red/# เพื่อสร้าง flow จากนั้นวาง node MQTT in หนึ่งตัว out สองตัว Inject node สองตัวและ debug node หนึ่งตัว ตามภาพ

ส่วนของการสร้าง flow ถ้าไม่คุ้นเลย แสดงว่าอ่านข้ามโพสต์ในส่วนนั้นมา ให้ย้อนไปศึกษาในโพสต์ก่อนหน้าเสียก่อน

image

ตั้งค่า MQTT in node ดับเบิ้บ คลิ๊กที่ตัว node

image

กดที่รูปปากกาเพื่อตั้งค่า mqtt-broker

image

ป้อนข้อมูลที่ได้จาก CloudMQTT Instance Info ,

Server ในช่อง Broker

User ป้อนในช่อง Client ID และ Username

Password ในช่อง Password

จากนั้นให้กดปุ่ม Add

สังเกตุตำว่า Add ความหมายคือ เราสามารถสร้าง MQTT Broker ได้หลายตัวใน flow ที่กำลังใช้งานอยู่ โดยเลือก Broker ที่ต้องการใช้ใน MQTT in หรือ out node

* mqtt-broker ที่เพิ่งสร้างนี้จะถูกนำไปใช้กับ MQTT node out ด้วย

เมื่ออกจากการเพิ่ม MQTT Broker เรียบร้อย ทำการเลือก Broker และทำการป้อน Topic เป็น livingroom/# (เป็นการรับข้อมูลทุกตัวที่ขึ้นต้นด้วย livingroom)

image

mqtt node out 2 ตัว ให้ตั้งค่า Topic เป็น livingroom/temperature กับ livingroom/humidity โดยเลือกใช้ Broker ตัวเดียวกันกับ mqtt node in

สำหรับช่อง Name จะใส่หรือไม่ก็ได้

image

สำหรับ inject node ทั้งสองตัวให้เลือกรูปแบบ String และใส่ข้อความในช่องถัดมาเป็นอะไรก็ได้ ให้แตกต่างกัน จะได้เห็นผลลัพธฺ์ที่ชัดเจน สำหรับผมใช้ temperature : 25.3 กับ Humidity : 50

image

ส่วนของ Debug node

image

หลังจาก deploy ให้ทดลองกดที่ inject node แต่ละตัว ดูผลที่ debug

ถ้ายังเปิด Websocket อยู่ จะเห็นผลเดียวกันแสดงในฝั่ง Received message ด้วย

จะเห็นว่าเมื่อเรามี user และ password แล้ว ไม่จำเป็นต้องทำอะไรอีก ก็สามารถใช้งาน MQTT ได้ทันที ยังไงก็ตาม ขอให้ทดลองปรับเปลี่ยนเพิ่มเติมในส่วนต่างๆ เพื่อให้สามารถนำไปประยุกต์ใช้งานในขั้นกว่าได้

สุดท้ายขอเน้นว่าทั้งหมดเป็น MQTT ที่ผมเข้าใจ และยังคงยืนยันคอนเซ็ปที่เนื้อหาที่เข้าใจได้ง่าย และสามารถนำไปปรับใช้ได้

สำหรับผู้ที่ติดตามอ่านแล้ว ติดขัดไม่เข้าใจตรงไหน สามารถโพสต์ในเฟส Node-RED Siam เพื่อให้เพื่อนๆได้แลกเปลี่ยนความรู้กันได้ครับ

วันอาทิตย์ที่ 13 กันยายน พ.ศ. 2558

Node-RED : รับสภาวะอากาศจาก openweathermap

 

Openweathermap เป็น node บริการข้อมูล ที่อัพเดทข้อมูลชองสภาพอากาศขณะเวลาปัจจุบัน จากสิ่งที่การระบุ เช่น ชื่อเมืองและประเทศ หรือ ตำแหน่งละติจูด ลองจิจูด

openweathermap จะส่งข้อมูลกลับคืนมาให้เลือกใช้ ได้แก่

ข้อมูล msg.payload

ลักษณะอากาศเป็นคำพูดง่าย (description)
ลักษณะอากาศแบบสั้นๆ (weather)
คำขยายความ (detail)
อุณหภูมิเป็นองศาเคลวิน (tempk)
อุณหภูมิเป็นองศาเซลเซียส (tempc) 
ความชื้น (humidity)
อุณหภูมิสูงสุดเป็นองศาเคลวิน (maxtemp)
อุณหภูมิต่ำสุดเป็นองศาเคลวิน (mintemp)
ความเร็วลม (windspeed)
ทิศทางลม (winddirection)
ชื่อเมือง (town)
เวลาพระอาทิตย์ขึ้น (sunrise)
เวลาพระอาทิตย์ตก (sunset)

ข้อมูล msg.location

เส้นละติจูด (lat)
เส้นลองจิจูด (lon)
ชื่อเมือง (city)
ชื่อประเทศ (country)

ข้อมูล msg.time แสดงเวลาที่รับข้อมูลจาก openweathermap.org

ข้อมูล msg.data ขีอมูลทั้งหมดในรูปแบบ JSON

image

สร้าง Node-RED อ่านค่าอุณหภูมิเป็นองศาเซลเซียส แสดงที่ debug ทุกๆ 10 นาที สามารถปรับให้ส่งเข้า tweeter หรือช่องทางอื่นๆได้ ให้ศึกษาจากโพสต์ที่ผ่านมา

inject

Payload : blank
Topic:
Repeat: interval, every 10 minnutes, ติ๊กถูกที่ Inject once at start?
Name:

openweathermap

Name:
Location: City,
     City: Bangkok,
     Country: Thailand

function

Name:
Function:
1    msg.payload = msg.payload.tempc;
2    return msg;
Outputs: 1

debug

Output: message property,
     msg.payload
to: debug tab
Name: tempc

ทำการ Deploy จากนั้นเปิดดูที่แท๊บ debug จะเห็นค่าอุณหภูมิของกรุงเทพที่ได้เลือกไว้

image

ทดลองนำข้อมูลอื่นๆแทนที่ tempc ใน function node จะเห็นว่าค่าที่แสดงไม่ได้บ่งบอกว่าคืออะไร ซึ่งเราสามารถจัดเรียงรูปแบบการนำเสนอใน template node ก่อนส่งไปแสดงที่ debug หรือส่งไปที่ช่องทางอื่นๆได้ เรื่องของ template เคยกล่าวไว้แล้วในโพสต์ก่อนหน้านี้

วันพฤหัสบดีที่ 10 กันยายน พ.ศ. 2558

NodeRED : ESP8266 กับ Webconfig

 

ผมเคยพูดถึงความไม่สะดวกในการนำ ESP8266 ไปใช้งานจริง เนื่องจากการนำไปใช้ในต่างสถานที่ ทั้ง SSID และ Password ที่เปลี่ยนไป จะทำให้ ESP8266 กลายเป็นที่ทับกระดาษ (แต่ขนาดเล็กอาจจะปลิวไปกับกระดาษ) แม้ว่าจะอยู่ที่เดิม แต่บางครั้ง DHCP server แจกจ่าย IP address ให้ต่างจากเดิม ก็จะไม่สามารถทำงานได้

 

ในส่วนที่ไม่ทราบหมายเลข IP ก็มีการนำ OLED ขนาดเล็กๆมาแสดงหมายเลข IP ก็สามารถแก้ไขได้ แต่ถ้าเราต้องการนำอุปกรณ์ไปใช้ในต่างสถานที่ มี SSID และ Password ต่างออกไป ก็ไม่สามารถนำวิธีการนี้ไปใช้ได้

 

หลายท่านคงเคยตั้งค่า router ที่สามารถเปลี่ยนค่าต่างๆได้ ด้วยการต่อสายแลน แล้วเปิด Browser ที่ 192.168.1.1 จะแสดงช่องต่างๆ ให้เราป้อนค่า และบันทึก

 

วิธีการข้างต้นเป็นการเขียนเวบ เหมือนที่เราเคยเขียนกัน และนำค่าที่เราป้อนไปบันทึกไว้ในหน่วยความจำ หน่วยความจำเป็นแบบบันทึกและล้างข้อมูลด้วยไฟฟ้า ชื่อย่อคือ EEPROM (Electrically Erasable Programmable Read Only Memory) จากการที่บันทึกและล้างข้อมูลด้วยไฟฟ้า ทำให้ข้อมูลยังคงอยู่แม้ไม่มีไฟเลี้ยง

 

ESP8266 มีหน่วยความจำรูปแบบนี้ขนาด 4K-bytes เพียงพอที่จะเก็บข้อมูล

 

ช่วงที่ผมเขียนบล็อก และได้ติดตามโพสต์ของ ESP8266 Thailand ก็ได้รับทราบจากเพื่อนสมาชิกท่านหนึ่งส่งลิ้งค์ไปที่ไซท์ของคุณ John Lassen ผมได้อ่านทำความเข้าใจแล้วเห็นว่ามีประโยชน์และสามารถต่อเนื่องบทความที่กำลังเขียนได้

 

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

image        image

http://www.john-lassen.de/index.php/projects/esp-8266-arduino-ide-webconfig

ผู้อ่านที่ต้องการศึกษาโดยละเอียด สามารถเข้าอ่านบทความเต็มได้จากลิ้งค์ด้านบน

 

ในส่วนที่นำมาเขียน จากเนื้อหาเดิมที่สลับซับซ้อน จึงได้นำเฉพาะส่วนที่จำเป็น มาปรับใช้ และในโพสต์ก็จะไม่ลงในรายละเอียดมากนัก โดยจะชี้จุดที่ผู้อ่านสามารถปรับเปลี่ยนโค๊ดให้เป็นไปตามต้องการ ผมได้วางโค๊ดที่ปรับแล้วไว้ตามลิ้งค์นี้

Download

หรือ

https://www.dropbox.com/s/ldszaffy6c1omwe/ESP_WiFi_AccessPoint.zip?dl=0

เปิดโค๊ดด้วย Arduino 1.6.2 และอัพโหลด ถ้าการทำงานเป็นปกติ ให้ทดลองเปิดดูรายชื่อ router ในมือถือหรือเครื่องคอมพิวเตอร๋ จะพบชื่อ ESP1

ให้ทำการเรียกใช้ ESP1 ด้วย password 12345678

จากนั้นให้เปิด Browser พิมพ์ 192.168.4.1 ซึ่งจะแสดงปุ่ม Configuration

image

เมื่อกดปุ่ม ก็จะแสดงหน้าข้อมูล ซึ่งสามารถเปลี่ยนข้อมูลและบันทึกได้ และจะกลับไปแสดงหน้าหลัก

image

ถ้าเราปล่อยหน้านี้ค้างไว้เป็นระยะเวลาตามที่กำหนดในตัวแปร AdminTimeOut เมื่อครบกำหนดจะเปลี่ยนจากโหมด AP (Access Point) มาเป็น Station mode ซึ่งต้องได้รับหมายเลข IP จาก router โดย ESP8266 จะใช้ค่าที่เราป้อนไว้ในช่อง SSID และ Password ในการเชื่อมต่อกับ router ถ้าค่าที่เราป้อนให้ไม่ถูกต้องก็จะไม่สามารถเชื่อมต่อกับ router ได้ การสังเกตุการทำงาน ให้เปิด Serial monitor ขณะทำการทดสอบ

เมื่อหมดเวลาที่แสดงคำว่า Admin Mode disabled และทำการเชื่อมต่อ ssid ชื่อ Sae-Ea-Dlink ใช้ password ที่บันทึกไว้

image

ถ้าการเชื่อมต่อกับ router สำเร็จ จะเห็นหมายเลข IP ที่ได้รับ แต่ถ้าไม่สามารถเชื่อมต่อได้ ก็จะเห็นเครื่องหมายจุดแสดงต่อเนื่องกันไป

การจะเข้าสู่โหมด Admin อีกครั้งให้ทำการปลดแหล่งจ่ายไฟสักครู่แล้วต่อเข้าไปใหม่

ค่าที่เก็บตัวอื่น ได้แก่ Private Key, Public Key, Fields ผมสร้างไว้เพื่อเก็บค่าที่ใช้ในการเชื่อมต่อกับ Phant (ผู้อ่านสามารถย้อนกลับไปทบทวนในบล็อกที่ผ่านมาได้

เมื่อต้องการเพิ่มเติม

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

ส่วนแรกที่ชี้จุดก็คือ การเพิ่มปุ่มในหน้าแรก เนื้อหาจะอยู่ในไฟล์ Page_Admin.h บรรทัดที่สนใจคือ

<a href="config" style="width:250px" class="btn btn--m btn--blue" >Configuration</a>

คุ้นๆกันนะครับ ก็เป็นการสร้างลิ้งค์นั่นเอง แต่ถ้าเราไม่มีส่วนของ class=”btn btn-m btn-blue” เราก็จะเห็นเพียงข้อความขีดเส้นใต้ ซึ่งก็สามารถทำงานได้เช่นกัน ในส่วนของการตบแต่งด้วย css จะไม่ขอกล่าวนะครับ ถ้าสนใจส่วนนี้ให้ศึกษาเนื้อหาในไฟล์ Page_Style.css.h

ทีนี้ลองเพิ่มปุ่มหนึ่งปุ่ม โดย copy บรรทัดด้านบน เปลี่ยน config เป็น test และ Configuration เป็น Testing

<a href="test" style="width:250px" class="btn btn--m btn--blue" >Testing</a>

ทดลองจะแสดง

image

และเมื่อกดดูจะแสดง Not found: /test เนื่องจาก server ไม่ได้ถูกกำหนดให้บริการ /test ซึ่งจำเป็นต้องไปเพิ่มเติมในไฟล์หลัก

image

ให้มองหาบรรทัด server.on("/config", handleConfig); และเพิ่มบรรทัดนี้ server.on("/test", handleTest);

นอกจากนี้ให้เพิ่มโค๊ดด้านล่างในไฟล์ Page_Config.h หรือสร้างไฟล์ใหม่แล้วบรรจุโค๊ดนี้เข้าไป แต่ต้องไม่ลืม #include ชื่อไฟล์ที่สร้างใหม่นั้นด้วย

void handleTest()
{
  server.send ( 200, "text/plain", "This is a test");
}

จากนั้นทดลองกดปุ่ม Testing คราวนี้จะเห็นประโยคที่เรากำหนดไว้

image

น่าจะพอมองออกนะครับว่า จะต้องเพิ่มอะไรไปบ้าง ในการสร้างปุ่มเมนูเพิ่มเติม

ต่อไปจะมาดูกันว่าเราสามารถจะนำค่าที่ต้องการไปเก็บ จะต้องทำอะไรตรงไหนกันบ้าง

ก่อนอื่นมาดูโครงสร้างของข้อมูลกันก่อน ในไฟล์ globals.h

struct strConfig {
  String ssid;
  String password;
  String DeviceName;
  String IoTPrivateKey;
  String IoTPublicKey;
  String IoTField;
}   config;

การเรียกใช้งานเพื่อเขียนหรืออ่าน จะเรียกตัวแปร config ตามด้วยเครื่องหมายจุด และตามด้วยชื่อสมาชิก เช่น

config.ssid = “ABC”;

และการอ่านค่าไปเก็บไว้ในตัวแปร เช่น

String ssid = config.ssid

เห็นแบบนี้แล้ว ก็ง่ายหละ ถ้าจะเพิ่มก็ทำการเพิ่มตัวแปรเข้าไป หรือไม่ใช้ก็ลบออก

แต่ว่าการเพิ่มการลบ ก็จำเป็นต้องไปเพิ่มหรือลบในตำแหน่งโค๊ดต่างๆ ดังนี้

ในไฟล์หลักที่ตำแหน่ง

if(!ReadConfig())
{
  config.ssid = "ssid";
  config.password = "password";
  config.DeviceName = "ESPNodeRED";
  config.IoTPrivateKey = "123456789";
  config.IoTPublicKey = "abcdef";
  config.IoTField = "f1,f2,f3";
  WriteConfig();
  Serial.println("General config applied");
}

ในไฟล์ Page_Config.h ที่แสดงตัวหนาไว้

void handleConfig()
{
  if(server.args() > 0)
  {
    Serial.println("Save configuration");
    String temp = "";
    for(uint8_t i = 0; i < server.args(); i++)
    {
      if (server.argName(i) == "ssid") config.ssid =   urldecode(server.arg(i));
      if (server.argName(i) == "password") config.password =    urldecode(server.arg(i));
      if (server.argName(i) == "privatekey") config.IoTPrivateKey =    urldecode(server.arg(i));
      if (server.argName(i) == "publickey") config.IoTPublicKey =    urldecode(server.arg(i));
      if (server.argName(i) == "fields") config.IoTField =    urldecode(server.arg(i));
      if (server.argName(i) == "devicename") config.DeviceName =    urldecode(server.arg(i));

    }
    server.send(200,"text/html",WaitAndReload);
    WriteConfig();
  }
  else
  {
    Serial.println("Show table");
    server.send(200, "text/html", Page_Config);
  }
  AdminTimeOutCounter = 0;
  Serial.println(__FUNCTION__);
}

void handleConfigValue()
{

  Serial.println("Retrieve values");
  String values ="";

  values += "ssid|" + (String) config.ssid + "|input\n";
  values += "password|" +  (String) config.password + "|input\n";
  values += "privatekey|" +  (String) config.IoTPrivateKey + "|input\n";
  values += "publickey|" +  (String) config.IoTPublicKey + "|input\n";
  values += "fields|" +  (String) config.IoTField + "|input\n";

  server.send ( 200, "text/plain", values);
  Serial.println(__FUNCTION__);
 
}

และในไฟล์ globals.h

void WriteConfig()
{
  Serial.println("Writing Config");
  EEPROM.write(0, 'N');
  EEPROM.write(1, 'R');
  EEPROM.write(2, '1');

  WriteStringToEEPROM(64, config.ssid);
  WriteStringToEEPROM(96, config.password);
  WriteStringToEEPROM(160, config.IoTPrivateKey);
  WriteStringToEEPROM(192, config.IoTPublicKey);
  WriteStringToEEPROM(224, config.IoTField);
  WriteStringToEEPROM(306, config.DeviceName);

  EEPROM.commit();
}

boolean ReadConfig()
{
  Serial.println("Reading configuration");
  if(EEPROM.read(0) == 'N' && EEPROM.read(1) == 'R' && EEPROM.read(2) == '1')
  {
    Serial.println("Configuration found!");
    config.ssid = ReadStringFromEEPROM(64);
    config.password = ReadStringFromEEPROM(96);
    config.IoTPrivateKey = ReadStringFromEEPROM(160);
    config.IoTPublicKey = ReadStringFromEEPROM(192);
    config.IoTField = ReadStringFromEEPROM(224);
    config.DeviceName = ReadStringFromEEPROM(306);

    return true;
  }
  else
  {
    Serial.println("Configuration NOT FOUND!!!!");
    return false;
  }
}

ทดลองปรับแก้และทดสอบดูกันนะครับ

ส่วนการนำไปใช้งาน ก็ให้นำค่าที่อยู่ในตัวแปร config ไปใช้ ได้ทุกจุดตามต้องการ ซึ่งในส่วนนี้จะนำเอาเนื้อหาในคราวนี้ ไปรวมกับเรื่อง Phant ให้ ESP8266 ทำงานได้แบบที่สามารถปรับเปลี่ยนค่าต่างๆได้ โดยไม่ต้องทำการโค๊ดกันทุกครั้ง จะนำเสนอในคราวต้อไป

สำหรับใครที่ต้องการประยุกต์ไปใช้งาน ต้องวางแนวคิดให้รัดกุมก่อน เพื่อให้การเขียนโค๊ดครั้งเดียว สามารถแปลงร่างให้ ESP8266 ทำงานให้เราได้ตามต้องการ เพียงตั้งค่าให้เหมาะสมเท่านั้น

วันอาทิตย์ที่ 6 กันยายน พ.ศ. 2558

Node-RED : JSON format

 

JSON หรือ JavaScript Object Notation

 

วันนี้ขอนำเสนอรูปแบบการจ้ดข้อมูลที่ใช้กันอย่างเป็นปกติของ IoT ตือรูปแบบข้อมูลแบบ JSON มีรูปแบบที่ง่าย ใช้งานได้อย่างมีประสิทธิภาพ โดยเฉพาะ NodeRED ก็ใช้รูปแบบนี้ในการบันทีกและค้นหาข้อมูล

JSON ใช้การจับคู่ที่เรียกว่า Key-Value pair โดยการวาง key หรือชื่อของข้อมูล ไว้ด้านซ้าย คั่นด้วยเครื่องหมาย semi colon ส่วน value หรือค่าจะอยู่ด้านขวา และมีสองแบบคือเป็น string ที่อยู่ในเครื่องหมายคำพูด และตัวเลข โดยตัว node เองจะตีความเอาว่าตัวเลขนั้นเป็นแบบไหน จำนวนเต็มหรือจำนวนจริง ซึ่งเป็นคุณสมบัติของภาษา javascripts นั่นเอง

ส่วนของการจัดวาง JSON จะประกอบ key-value pair อย่างน้อย 1 ชุด นำหน้าด้วยเครื่องหมายวงเล็บปีกกาเปิด และปิดท้ายด้วยวงเล็บปีกกาปิด

{ “key”:”value” }

โดยเรียกรูปแบบนี้ว่า JSON Object

ในหนึ่ง object สามารถประกอบด้วยหลาย key-value pair โดยคั่นแต่ละชุดด้วยเครื่องหมาย comma

{ “key1”:”value1”, “key2”:”value2”}

จำนวนคู่ จะขึ้นอยู่กับความยาวของตัวอักษรรวม ไม่ให้เกินจำนวนตัวอักษรสูงสุดของตัวแปรแบบ string ของภาษาโปรแกรที่เราใช้งาน

นอกจาก object แล้วยังมีรูปแบบ array ที่ประกอบด้วย object หรือ/และ array หลายๆตัวประกอบกันคั่นด้วยเครื่องหมาย comma เช่นกัน การบ่งบอกว่าเป็น array ด้วยการเปิดปิดด้วยวงเล็บเหลี่ยม [ ….. ]

{ “array” : [ {“obj1”:”val1”} , {“obj2”:”val2”} ] }

การแปลความจะได้ว่า เป็น array ที่มีสมาชิก 2 ตัว ชื่อของ array คือ array

array[0] = {“obj1”:”val1”}
array[1] = {“obj2”:”val2”}

ข้อสังเกตุ JSON จะเป็น object จึงเริ่มต้นด้วยเครื่องหมายปีกกา และสามารถประกอบด้วย object และ array สลับไปมาด้วย

{ “obj1”:”val1”,”obj2”:”val2”,”arr1” : [ {“obj3”:”val3”,”obj4”:”val4”},{“obj5”:”val5”,”obj6”:”val6”} ] }

ประกอบด้วย 3 object โดย arr1 เป็น array มีสมาชิก 2 ตัว แต่ละตัวมี object สมาชิกอยู่ 2 ตัว

array สามารถสร้างได้หลายมิติ การจัดวาง object หรือ array ไม่ถูกต้อง จะเกิดข้อผิดพลาดตอนใช้งาน

ใน NodeRED เราจะใช้รูปแบบ JSON ได้ตลอดเวลา ในการแปลงข้อมูลไปมา ใน function node ถ้าไม่มีความเข้าใจในรูปแบบ JSON แล้ว อาจมีความยุ่งยากในการเขียนโปรแกรม

ในภาษาโปรแกรมส่วนใหญ่จะสร้างไลบรารี่ในการสร้าง (encoding) และตีความ (decoding) หลายที่ใช้คำว่า parser

ส่วนของ Arduino ผมใช้ไลบรารี่ ชื่อ ArduinoJson ในการ parse ข้อมูล JSON อย่างไรก็ตาม ด้วยที่ JSON เป็นการนำเสนอข้อมูลแบบตัวอักษร ทำให้เราสามารถเข้าใจได้ง่าย

ในส่วนของการใช้งาน คงจะแฝงไปในเนื้อหาของโพสต์ แต่ละโพสต์

 

 

 

 

วันศุกร์ที่ 4 กันยายน พ.ศ. 2558

Node-RED – มี IoT Cloud ในบ้าน ก็สะดวกดี


เปิดตัว Node-Red Siam มาได้ไม่กี่วัน (เปิดตัววันที่ 3 ก.ย.)  ก็ได้มีการแลกเปลี่ยนกัน ส่วนใหญ่จะถามหา node widget ของอุปกรณ์แต่ละตัว ตอนที่ลงเรื่องเชื่อมต่อกับ tweeter ก็ถามว่ามี facebook ด้วยหรือป่าว
สำหรับด้าน hardware ผมได้โพสต์ในเรื่องการเชื่อมต่อ NodeRED กับ Arduino ไปแล้ว ลองย้อนไปอ่านดูได้ครับ แต่ด้วยระยะนี้ ESP8266 กำลังมาแรง ก็มีถามหา node widget ของตัวนี้มาด้วยเช่นกัน
สำหรับ ESP8266 โดยความเห็นส่วนตัวแล้ว จะมีใครเห็นด้วยหรือไม่ก็แลกเปลี่ยนกันได้ครับ สิ่งที่ผมมอง ESP8266 ก็คือ IoT devices ตัวหนึ่ง ที่อาจจะเอาไว้ทำหน้าที่เป็น input หรือ output หรือแสดงค่าหรือปรับเปลี่ยนค่าทาง analog เช่น อุณหภูมิ ความชื้น ความสว่าง การที่จะให้มันทำงานทุกอย่างในตัวเดียว อาจจะให้มันแบกภาระเกินตัว คือให้มันเป็นทั้ง server เป็นทั้ง IO เผลอๆให้มันเป็น datalogger ไปด้วย
การที่ให้ ESP8266 ทำงานทุกอย่างทั้งหมด ทำได้แน่นอน สิ่งที่ตามมาก็คือ ขาดความยืดหยุ่น จำเป็นต้องเรียนรู้ทุกอย่างถึงแกนของตัวมัน เพื่อให้มันสามารถที่จะทำงานให้เราได้และมีความน่าเชื่อถือ (ความเสถียร) สำหรับผู้พัฒนาเองจะติดหนึบอยู่กับการทำ programming ชิ้นงานที่ออกมาจะใช้ได้เฉพาะงานนั้น การปรับให้ทำงานอิ่นก็จะต้องลงมือแก้ไขโปรแกรมกัน ทำให้การส่งชิ้นงานออกตลาดอาจช้ากว่าความต้องการ
ถ้าเราทำการแยกผลิตภัณฑ์ออกเป็นหมวดหมู่ แล้วสร้างอุปกรณ์ในแต่ละหมวดมู่ โดยอุปกรณ์แต่ละตัวจะเป็น generic devices สามารถปรับตั้งค่ามันได้ง่ายๆ ด้วยการเชื่อมต่อตัวมันกับเครื่องมือปรับตั้งค่า เมื่อจบกระบวนการ generic devices ตัวนั้นก็จะกลายเป็น specific devices ไปทำหน้าที่อย่างที่เราต้องการให้มันเป็น ไปเป็นหมอ เป็นทหาร เป็นตำรวจ อะไรก็ว่ากันไป นึกไปแล้วก็เหมือนกับหนังเรื่อง iRobot ที่หุ่นแต่ละตัวมีหน้าตาเหมือนกันหมด แต่บทบาทหรือหน้าที่ต่างกัน
หลายคนคงคิดว่า ผมกำลังพูดอะไร คือผมกำลังพูดถึงแนวคิดหรือ concept ของ IoT ที่จะไม่ผูกติดอะไรเอาไว้ในจุดๆเดียว สอดคล้องกับที่ทั่วโลกกำลังทำ utility หรือ service ต่างๆ ให้เราได้ใช้ ยกตัวอย่างการทำงานกับเอกสารหรือข้อมูล ยุคนี้เราไม่จำเป็นต้องเอาโน๊ตบุ๊กที่ใช้งานในออฟฟิสติดตัวเราไปทุกที่ เพราะเราสามารถใช้คอมพิวเตอร์ที่ไหนก็ได้ เปิด web application (word, excel) จากนั้นก็ล๊อกอินเพื่อเปิดฐานข้อมูลของเราที่ฝากไว้กับ cloud data server ก็สามารถทำงานได้แล้วจากทุกๆที่
ทีนี้ลองย้อนมาดูในส่วนของ ESP8266 ถ้าเราต้องการให้มันเป็น generic devices เราก็ควรจะต้องทำอะไรบ้าง เพื่อให้มันทำงานได้ หลังจากถูกแปลงร่างเป็น specific devices
จากประสบการณ์ที่ได้ติดตามอ่านโพสต์ต่างๆในเฟสบุ๊กของหลายกลุ่ม จะติดปัญหาในเรื่องของหมายเลข IP เพราะตัวเลขนี้ถ้าตั้งเป็น static ก็อาจจะไม่เกิดความยืดหยุ่น แต่ถ้ารับค่าจาก DHCP server ก็จะไม่รู้ว่าตัวเองได้รับหมายเลขอะไรมา ก็เลยมีการต่อจอ OLED มาเพื่อให้แสดงหมายเลข IP หรือต้องไปกำหนดค่าใน WiFi server เพื่อล๊อกค่า IP ให้กับ MAC address ของ ESP8266 ตัวนั้น ถ้ามีตัวเดียว หรือสองตัวก็คงไม่ยากนัก แต่ถ้าเป็น Home automation อย่างน้อยก็คงเป็นสิบตัวขึ้นไป ตัวบอร์ดขนาดเล็กๆของ ESP8266 ก็เลยต้องอ้วนขึ้น เพราะมีจอ OLED มาต่อด้วย เนื่องจากไม่ต่อก็ไม่รู้จะสั่งงานไปที่ IP ไหน
สมมุติว่าเรามี generic devices แบบหนึ่ง อยู่ในหมวด input แล้วเราตั้งชื่อให้มันว่า IN และเสริม Dip switch ปรับตั้งหมายเลขตั้งแต่ 0-15 ต้องการให้ตัวนี้ชื่อ IN3 ก็บิด dip switch ไปที่เลข 3 รีเซทอุปกรณ์ 1 ครั้ง ตอนนี้มันก็จะรู้ว่ามันชื่อ IN3 ถามว่าแล้วการจะส่งข้อมูลหละ IN3 ก็จะเริ่มทำงานแล้วส่งข้อมูลไปที่ cloud data server ตามคาบเวลาที่กำหนด ในนามของ IN3 สำหรับในส่วนของ dashboard ที่เชื่อมต่อกับ cloud data server ก็จะทำการอ่านข้อมูลของ IN3 แล้วทำการแสดงผล
จะเห็นได้ว่าเราไม่จำเป็นต้องรู้ว่า IN3 มีหมายเลข IP เป็นอะไร รู้แต่ว่าอุปกรณ์ตัวนั้นชื่ออะไร เราก็สามารถบริหารข้อมูลของอุปกรณ์ตัวนั้นได้แล้ว
ทีนี้การจะตั้งชื่อให้กี่ตัวก็แค่เพียงบิด dip switch ไปที่ตำแหน่งนั้น ซึ่งทำได้ถึง 16 ตัว เป็น output devices ได้อีก 16 ตัว บ้านขนาดกลางๆ 1 หลังก็น่าจะเพียงพอ
การทำผลิตภัณฑ์ในรูปแบบนี้จะลดความยุ่งยากไปได้มาก ได้เวลาไปพัฒนาผลิตภัณฑ์อืนๆ อีกมากโข
มาถึงจุดนี้ น่าจะมองเห็นภาพที่ฉายไปได้พอสมควร คำถามต่อไปก็คือ แล้ว cloud data server หละ ในโพสต์ก่อนหน้า ได้แนะนำไป เช่น บริการของ Thingspeak หรือตัวที่ผมนิยมคือ Dweet.io ก็ยังมีของ Sparkfun ในโครงการ Phant
การใช้ server ภายนอกที่น่าเชื่อถือ ก็ยังมีโอกาสที่ server ล่ม เราคงต้องพบปัญหาเปิดไฟ ปิดไฟไม่ได้ ซึ่งก็เป็นจริงตามนั้น แม้ server ไม่ล่ม หรือไม่บริการ ADSL มีปัญหา ถ้าเราจำเป็นต้องพึ่ง cloud data server ภายนอก คงวุ่นวายน่าดู ครับเป็นอย่างที่คุณคิดนั่นแหละ ถึงจุดนี้เราต้องมี cloud data server ของเราเองจะดีเป็นแน่ อยากจะเรียกให้หรูว่าเป็น In house cloud data server
In house cloud data server อันนี้แหละเป้นเนื่อหาที่ผมขอนำมาเสนอในโพสต์นี้ มาแนะนำการติดตั้ง cloud data server กัน บอกได้เลยว่าง่ายมากๆ
ความเป็นมาของโพสต์นี้ก็คือ ผมได้โต้ตอบกับคำถามเรื่องของ ESP8266 node widget ที่จะมาใช้งานกับ NodeRED ซึ่งผมก็ได้ออกความคิดเห็นในลักษณะที่ได้เขียนไว้ด้านบน แต่อาจจะอธิบายความไม่ได้มากนัก จึงเก็บเรื่องนั้นมาโพสต์ต่อในบล๊อก ในโพสต์นั้นได้มีสมาชิกท่านหนึ่งได้แนะนำ cloud data server ที่สามารถนำมาติดตั้งไว้บน PC เพื่อการบริหารข้อมูล มีเครื่องไม้เครื่องมือให้ใช้ครบ ชื่อเรียกคือ phant เป็นโครงการของ Sparkfun ที่ได้พัฒนาขึ้นและทำการแจกจ่ายแบบไม่คิดเงิน ให้สามารถนำมาติดตั้งบน PC ที่รัน Node.js อยู่ ได้ใช้งานกัน
ผมได้ทำการติดตั้ง phant เป็นที่เรียบร้อย ด้วยคำสั่งที่คุ้นเคย
npm install phant –g
ขอเน้นในเรื่อง –g เนื่องจากมันจะถูกใช้ในลักษณะ global คือทุกแอปสามารถเรียกใช้งานได้ ถ้าไม่มี –g อาจทำให้เกิดปัญหาในการใช้งานกับแอปอื่นๆ
ติดตั้งเรียบร้อยแล้วก็เรียกใช้งานด้วยคำสั่ง phant ใน Command prompt console แนะนำให้เรียก console เป็นแบบ Administrator ครับ
ถ้าการติดตั้งสมบูรณ์ก็จะมีข้อความแสดงบน console ตามนี้
phant http server running on port 8080
phant telnet server running on port 8081

แล้วก็จะค้างอยู่แบบนั้น แสดงว่าการทำงานเริ่มขึ้นแล้ว
แต่หนทางไม่ได้โรยด้วยกลีบกุหลาบ ผมประสบปัญหาตอนเรียกใช้งาน ตามภาพที่แสดงเลยครับ
image
ทดลองกี่ครั้งก็ไม่ได้ อันนี้ขอบอกว่าของท่านอื่น ติดตั้งแล้วอาจไม่พบปัญหานี้ก็เป็นไปได้
เนื้อหาของข้อผิดพลาดก็ไม่ได้บอกอะไรมาก ตอนนี้ก็ต้องเดาเหตุการณ์เอา ซึ่งเป็นโชคดีที่ผมเดาถูก สิ่งที่ผมคิดก็คือ หมายเลขพอร์ทน่าจะชนกับ server ตัวอื่น เพราะหมายเลข 8080 เป็นที่นิยมใช้กันมากสำหรับ http server คิดได้อย่างนั้นก็เลยต้องหาว่า แล้วจะเปลี่ยนหมายเลขพอร์ทได้ที่ไหน ค้นไปสักพักก็ไปพบกับไฟล์ชื่อ serve อยู่ในโฟลเดอร์ที่ติดตั้ง phant
ในรูป console ด้านบนจะเห็นชื่อโฟลเดอร์ยาวๆ ให้เข้าไปที่ตำแหน่งนั้น แต่แทนที่จะไปที่ lib ให้เข้าไปที่ _bin แทน จะพบกับไฟล์ชื่อ serve ให้เปิดไฟล์ด้วย text editor แล้วหาบรรทัดที่มีข้อความ
http_port = process.env.PHANT_PORT || 8080,
telnet_port = process.env.PHANT_TELNET_PORT || 8081;
จัดการเปลี่ยนหมายเลข 8080 เป็นหมายเลขอื่น ของผมใช้ 8090 และ 8091 สำหรับ telnet บันทึก แล้วทดสอบ ถ้าไม่ได้ก็เปลี่ยน จนสามารถเปิดใช้งานได้
สองบรรทัดที่นำมาแสดงจะเห็นว่ามีการใช้ process.env.PHANT_PORT และ process.env.PHANT_TELNET_PORT ซึ่งถ้าเป็นผู้เชี่ยวชาญเรื่อง OS ก็จะสามารถไปปรับตั้งค่าได้ แต่ผมแนะนำให้ใช้วิธีนี้
เริ่มต้นใช้งาน PHANT
ก่อนจะดำเนินเรื่องต่อไป มีเกร็ดเล็กๆของชื่อ PHANT ที่ Sparkfun บอกว่ามาจากคำว่า Elephant ที่แปลว่า ช้าง ซึ่งเป็นสัตว์ที่มีความจำดี ก็เลยนำเอาชื่อมาใช้ในการเก็บข้อมูล สัญญลักษณ์ของโครงการก็เป็นรูปคล้ายๆช้าง
เอาหละมาเริ่มใช้งาน
ให้เปิด browser พิมพ์ http://127.0.0.1:8080 ตัวเลข 8080 จะเป็นเลขอื่นตามที่เราได้แก้ไข จะแสดงหน้าจอ
image
Phant พร้อมทำงานแล้ว ลองอ่านคำอธิบายกันสักหน่อย ด้านท้าย จะเห็น
image
การใช้งานหลักๆ มีอยู่สองส่วนคือ
image      image
CREATE สำหรับการสร้าง data และ EXPLORE สำหรับค้าหา data
ทำการสร้าง data
ให้กดที่ CREATE หน้าจอแสดงฟอร์ม ให้ป้อนข้อมูลที่จำเป็น ได้แก่
Title, Description, Show in Public Stream List และ fields ในช่อง fields ให้ใส่ชื่อฟิลด์ต่างๆ โดยคัั่นด้วย comma
ตัวอย่าง ตั้งชื่อ คำอธิบาย และ ฟิลด์ led relay และ servo
image
ส่วนของ Tags และ Location สามารถป้อนและเรียกดูได้ ใส่ไว้ก็ดีหรือไม่ใส่ก็ได้ สำหรับ Stream alias แนะนำให้ใส่ตั้งชื่อไว้ เพื่อให้สามารถเรียกดู data stream โดยอ้างชื่อนี้ได้ ผมใส่คำว่า NodeRedStream เอาไว้ จากนั้นทำการบันทึก
Phant จะสร้าง data stream ให้ และแสดงข้อมูลที่สำคัญ ในหน้าถัดไป จำเป็นต้องบันทึกค่าเหล่านี้ไว้ ส่วนที่สำคัญที่สุดคือ Private key เพราะจะต้องใช้ในการแก้ไขการตั้งค่า บันทึกหน้าจอไว้ก็จะดีครับ ส่วนของด้านล่างแสดงวิธีการเขียนลงในโค๊ด เพื่อการบันทึก เรียกดู หรือลบ data stream จะแสดงวิธีการใช้โค๊ดตอนเราใช้งานใน NodeRED editor
ทบทวนกันนะครับ ตอนนี้เราสร้าง data stream บน Phant ประกอบด้ว 3 ฟิลด์คือ led, relay และ servo
วิธีการบันทึกข้อมูล
รูปแบบ
http://127.0.0.1:8090/input/PUBLIC_KEY?private_key=PRIVATE_KEY&FIELD1=VALUE1&=FIELD2=VALUE2
ให้แทนที่ PUBLIC_KEY, PRIVATE_KEY ด้วยค่าที่เราบันทึกไว้ และใส่ชื่อ FIELD1, FIELD2 และ FIELD3 ตามที่เราตั้งไว้ สำหรับที่ผมทำจะเป็นตามนี้
http://localhost:8090/input/W8zJbQ8bPjcX8WlYpvEEt2xVlO9?private_key=0w60z7wzyQfLMA5wZXPPFAze628&led=5.44&relay=12.03&servo=28.37
หมายเลข PUBLIC KEY และ PRIVATE KEY จะแตกต่างจากด้านบนนะครับ ของใครของมัน
ทีนี้มาดูการเรียกดูค่าที่เราป้อนเข้าไป มี 2 รูปแบบ
ถ้าในไปใช้ในโค๊ด จะเป็นรูปแบบนี้
http://localhost:8090/streams/W8zJbQ8bPjcX8WlYpvEEt2xVlO9
รหัสต่อท้ายเป็น PUBLIC KEY
หรือดูบน browser ก็
http://localhost:8090/noderedpoint
noderedpoint คือ Stream alias ที่เราตั้งชื่อ
ทั้งสองรูปแบบจะแสดงผลเป็นลักษณะนี้
image
จะแสดงค่าที่เราเพิ่งส่งเข้าไป สังเกตุที่มุมบนขวาจะมีปุ่ม Manage เพื่อเข้าไปแก้ไขการตั้งค่า จะเข้าได้ต้องป้อน Private key
image
จะเห็นได้ว่า Private key สำคัญมากๆ ต้องใช้ในหลายส่วน
การปรับค่าก็จะเป็นหน้าเดียวกับการสร้าง แก้ไขแล้วก็ทำการบันทึก
สำหรับการใช้งานกับ NodeRED ขอยกไปโพสต์ต่อไป โพสต์จะได้ไม่ยาวเกินไป

วันพฤหัสบดีที่ 3 กันยายน พ.ศ. 2558

Node-RED - คุยกับ Arduino ผ่าน Serial port อาศัย Firmata protocol


Node-RED มี nodes ที่ใช้ในการเชื่อมต่อกับ Arduino โดยอาศัย Firmata protocol
วิธีการติดตั้ง เหมือนกับการติดตั้ง Dweetio ของตอนที่แล้ว ผ่านทาง npm
ติดตั้ง Arduino nodes
ไปที่ user directory พิมพ์คำสั่ง
npm install node-red-node-arduino
เปิด NodeRed server
เปิด nodered ด้วย browser
image
จะพบแท๊ป Arduino ประกอบด้วย Arduino in และ Arduino out
Arduino in เหมือนกับ Dweetio in จะถูกกระตุ้นเมื่อมีการเปลี่ยนที่ pin ที่กำหนด
Arduino out จะส่งคำสั่งไปที่ pin ที่กำหนด อาจจเป็น on-off digital pin ตั้งค่าให้กับ Analog pin และตั้งค่าให้กับ Servo pin
ลง Firmata ให้กับบอร์ด Arduino
ก่อนใช้งานให้เปิดตัวอย่าง Firmata เลือก StandardFirmata และ upload ไปที่ Arduino board เพื่อให้สามารถรับคำสั่งและส่งผลกับ Node-RED จะเป็นบอร์ด UNO หรือ Nano หรือบอร์ดรุ่นอื่นๆก็ได้
สร้าง Flow เพื่อทดสอบ

image
ตามรูปครับ
สำหรับ Node Pin2 ให้ตั้งค่าตามนี้
image
ในช่อง จะเห็นชื่อพอร์ทที่บอร์ดต่ออยู่ หรือ Add new arduino-board… ให้กดที่รูปดินสอ Node-RED จะตรวจหาบอร์ด Arduino แล้วแสดงชื่อพอร์ทให้เลือก
image
เลือกพอร์ทที่บอร์ดต่ออยู่ กด update จะย้อนกลับมาที่หน้าตั้งค่า เลือก pin = 2 Type = Digital pin กด OK เป็นการเลือก pin 2 เป็น digital pin การทดสอบให้หารีซิสเตอร์ค่าประมาณ 1 – 10K ต่อระหว่าง pin 2 กับ GND การลอย pin 2 ไว้จะทำให้มีการส่งค่าที่ไม่สามารถคาดเดาได้
จากนั้นให้นำสายจั้มเปอร์อีกเส้นหนึ่งเชื่อมที่ pin 2 ไว้ เพื่อตอนทดสอบจะเลือกให้ต่อกับ +5v หรือ GND
Node Arduino out เลือก pin 13 หมายเลข Arduino ใช้อันเดียวกันกับ Node Pin 2 จริงแล้วก็ใช้พอร์ทเดียวกันทั้ง Flow
image
สำหรับ Node Pin A0 ใช้รับค่าจาก Analog pin A0 
image
เชื่อมต่อกับ debug node เพื่อแสดงค่า
จากนั้น deploy
จะเห็นค่าที่ Pin A0 รับมาถูกแสดงที่ debug แท๊ป เป็นค่าที่เกิดจากสัญญาณรบวน อาจต่อรีซิสเตอร์จาก pin A0 กับ GND ไว้เพื่อตัดสัญญาณรบกวน
ให้ทดลองต่อสายจั้มเปอร์ที่ pin 2 กับ +5v หรือ GND ที่แท๊ป debug จะแสดง True และ False ตามที่เราทำ อาจจะสังเกตุยาก ให้นำสายจั้มเปอร์ต่อ pin A0 กับ +5v หรือ GND ค่าที่แสดงให้กับ pin A0 จะไม่อัพเดท เพราะค่าไม่เปลี่ยนแปลง แล้วทดลองกับ pin 2 จะเห็นว่าหลอด LED ที่ต่อกับ pin 13 จะติดดับตามที่เราทำกับสายจั้มเปอร์ของ pin 2 ด้วย
อาจนำรีซิสเอร์ปรับค่าได้ ปรับค่าแรงดันไฟฟ้า ให้กับ pin A0 แล้วดูผล
ส่วนของ Servo อาจนำค่าที่รับจาก pin A0 ค่า 0 – 1023 มาปรับให้มีค่าเป็น 0 – 180 แล้วส่งไปที่ servo pin จะเห็นการขยับของแกน servo
สำหรับ Hardware node จะมี Raspberry pi และ Beagle bone ด้วย แต่ผมไม่มีบอร์ดจะนำมาทดสอบ



Node-RED - Datalogger และเพิ่ม Dweet.IO nodes

 
Datalogger เป็นส่วนหนึ่งในการดูแลระบบ นอกเหนือจากการส่งข้อมูลแจ้งเตือนไปที่ tweeter และ Email
ข้อมูลเมื่อมีข้อมูลใหม่เข้ามหรือช่วงเวลาที่กำหนดก็เป็นส่วนที่สำคัญ Node-RED ก็ไม่ได้ขาดจุดนี้ วิธีการท่จะนำเสนอต่อไปนี้ไม่ได้เป็นวิธีเดียวเท่านั้น โดยเป็นการนำข้อมูลไปเก็บไว้เป็นรูปแบบเท็กไฟล์ ง่ายและสะดวก แต่ถ้าจะเก็บเป็นรูปแบบฐานข้อมูลก็จะมี mongoDB มาช่วย ส่วนของโพสต์นี้จะพูดในการทำรูปแบบข้อมูลและนำไปบันทึกเป็นรูปแบบไฟล์เท่านั้น
คงจะไม่ลืมว่าเราเคยทำการฝากข้อมูลไว้ที่ Dweet.io บันทึกและนำเข้ามูลมาใช้งานกันมาแล้ว
คราวที่แล้วเราเรียกใช้งานผ่าน http request nodes ก็ใช้งานได้ในระดับหนึ่ง จะเห็นว่า Dweet.io ไม่มีใน nodes มาตรฐานใน editor (ใน FRED มีอยู่) แต่ข่าวดีเรามีคนสร้างไว้ให้เราใช้ ซึ่งสามารถทำการติดตั้งได้โดยง่าย ตามกันไปเลยครับ
เปิด Node-RED server มองหาบรรทัดที่ขึ้นต้นด้วย User directory 
ปิด Node-RED server ด้วย Ctrl + C 
จากนั้นเปิด Command prompt แบบ Admnistrator เข้าไปที่ User directory และพิมพ์คำสั่ง
npm install node-red-node-dweetio
* เพิ่มเติม เราควรเพิ่ม –g ในการติดตั้ง เพื่อให้ทุก user สามารถใช้งานได้
npm install –g node-red-node-dweetio

รอจนติดตั้งเรียบร้อย สำรวจดูจะพบ directory ชื่อ  node-red-node-dweetio ใน directory ชื่อ node_modules เป็นอันเสร็จสมบูรณ์
เปิด Node-RED server แล้วเปิดใช้ Node-RED editor ด้วย browser 
จะพบ Dweet.io nodes ในแท็ป input เป็น dweetio in และในแท๊ป output เป็น dweetio out
image          image
dweetio in nodes จะได้รับการกระตุ้นให้แสดงผล เราสามารถแสดงผลลัพธ์ผ่าน debug nodes และสามารถปรับ
รูปแบบของผลลัพธ์ผ่าร function nodes ก่อนทำการบันทีกได้ด้วย
ผมขอตั้งชื่อ thing เป็น noderedsupotsaeea
ดังนั้นการเก็บข้อมูลเข้า thing นี้ สามารถพิมพ์ที่ browser address ตามนี้
ถ้าตั้งชื่อ thing เป็นอื่นๆ ก็นำไปใส่แทน noderedsupotsaeea ได้เลย
สร้าง flow ตามรูป
image
1. dweetio in nodes
image

2. function nodes
image
ช่อง function พิมพ์คำสั่ง javascripts
var date = new Date();
msg.payload = {date:date.toISOString(), data:msg.payload.val, created:msg.created, thing:msg.thing};
return msg;


3. debug nodes
image

4. template nodes
image
พิมพ์ Date: {{payload.date}}, value={{payload.data}} ในช่อง Template

5. files nodes
image
จะทำการบันทึกข้อมูลลงไฟล์ชื่อ datalogger.txt ในโฟลเดอร์ data ในไดรว์ d:
ถ้าไม่พบโฟลเดอร์จะทำการสร้างให้
ทำการ deploy flow
จากนั้นทำการทดลอง

จะพบว่าเมื่อมีการอัพเดทข้อมูล dweetio in จะถูกกระตุ้นให้ทำการอ่านข้อมูลผ่านไปที่ function nodes
เพื่อดึงข้อมูลที่ต้องการนั่นคือ val และ thing ทำการสร้างวันที่ เวลาปัจจุบัน เก็บค่าไว้ที่ตัวแปร date
และปรับสภาพของข้อมูลด้วย template nodes ก่อนการบันทึกลงไฟล์ด้วย file node

เพียงเท่านี้เราก็สามารถบันทึกข้อมูลทุกครั้งที่มีการเปลี่บยแปลงค่าของ thing
คราวนี้เราได้วิธีการเพิ่ม dweetio nodes ซึ่งเป็นวิธีการมาตรฐาน
ฝากเรื่องไว้ว่าจะทำอย่างไร ถ้าต้องการบันทึกข้อมูลตามคาบเวลา แทนที่จะรอการกระตุ้น น่าจะนำเอา
dweetio out มาช่วยครับ

วันอังคารที่ 1 กันยายน พ.ศ. 2558

Node-RED - Host สำหรับ Node-RED

ดูเหมือนว่าอะไรที่เรากำลังคิดก็ถูกคิดโดยคนอื่นด้วยเช่นกัน เรื่องของเรื่องก็คือ
เห็นข้อจำกัดที่ว่าตัว Node-RED ต้องทำงานอยู่บนเครื่องคอมพิวเตอร์ของเรา
ถ้าไม่เปิดเครื่องก็ใช้งานไม่ได้ ก็เลยลองหาดูว่ามี Hosting จ้าวไหนที่สามารถนำ
Flow ของเราไปฝากให้ทำงานได้บ้าง ผลคือหาไม่ได้ อย่างดีก็สามารถทำ Node.js
เพื่อสร้าง web application ซึ่งต้องทำการติดตั้ง
อะไรต่ออะไรอีก ไม่ตรงกับ concept ของเราที่จะต้องเป็นอะไรที่ไม่ยุ่งยาก
แต่ก็อย่างที่เกริ่นไว้ว่ามีคนคิดแบบเรา แล้วก็ทำแล้ว ที่ดีกว่านั้นก็คือ ฟรี เสียด้วย
อันนี้ตรงกับ concept ของเราเป๊ะ

โชคดีสำหรับคนที่ไม่ถนัดที่จะติดตั้งโน่นนี่ ยังไงก็อ่านวิธีการติดตั้งผ่านๆบ้างก็ดี

ตามที่ได้โพสต์ไว้ในโพส์แรกๆ คราวนี้คุณก็สามารถข้ามขั้นตอนเหล่านั้นไปได้
แล้วมาเล่นกับ Node-RED ได้เลย ทุกสิ่งอย่างเหมือนกันหมด เพราะเค้าเอา Node-RED
ไปติดตั้งไว้ใน Host ที่ถือว่าเป็นการเฉพาะสำหรับ Node-RED จริงๆ
หลังจากสมัครแล้วเปิดใช้งานก็จะว้าวกันเลย
อีกอย่างคือมี widget ให้เราเลือกใช้นอกเหนือจาก widget มาตรฐานอีกเพียบ

image


Sensetecnic มีผลิตภัณฑ์ดีๆ นอกเหนือจาก FRED (Front-End for Node-RED)

ที่เรากำลังจะสมัครใช้
ส่วน WoTKit เองก็เป็นอีกตัวหนึ่งที่มี Dashboard และ Sensor data ให้เราใช้
ตัวนี้ขอเวลาศึกษาสักพัก แล้วจะมาโพสต์เพิ่มเติม
image
สมัครใช้งานกันได้ครับที่ https://fred.sensetecnic.com/
เรียบร้อยแล้วก็จะเข้าไปที่หน้าแรก แล้วก็เรียกใช้งานได้เลย
image
โพสต์นี้มาแนะนำเครื่องมือครับ
ส่วนเนื้อหาของ Node-RED ติดตามกันต่อในโพสต์หน้าครับ