{"id":5479,"date":"2019-01-28T16:12:00","date_gmt":"2019-01-28T07:12:00","guid":{"rendered":"https:\/\/www.lancard.com\/blog\/?p=5479"},"modified":"2025-03-12T11:26:05","modified_gmt":"2025-03-12T02:26:05","slug":"%e8%b5%a4%e5%a4%96%e7%b7%9a%e3%82%a2%e3%83%ac%e3%82%a4%e3%82%bb%e3%83%b3%e3%82%b5%e3%83%bc%e3%80%8cmlx90640%e3%80%8d%e3%82%92esp32%e3%81%ab%e3%81%a4%e3%81%aa%e3%81%84%e3%81%a7websocket%e3%81%97","status":"publish","type":"post","link":"https:\/\/www.lancard.com\/blog\/2019\/01\/28\/%e8%b5%a4%e5%a4%96%e7%b7%9a%e3%82%a2%e3%83%ac%e3%82%a4%e3%82%bb%e3%83%b3%e3%82%b5%e3%83%bc%e3%80%8cmlx90640%e3%80%8d%e3%82%92esp32%e3%81%ab%e3%81%a4%e3%81%aa%e3%81%84%e3%81%a7websocket%e3%81%97\/","title":{"rendered":"\u8d64\u5916\u7dda\u30a2\u30ec\u30a4\u30bb\u30f3\u30b5\u30fc\u300cMLX90640\u300d\u3092ESP32\u306b\u3064\u306a\u3044\u3067WebSocket\u3057\u3066\u307f\u307e\u3057\u305f"},"content":{"rendered":"<p><a href=\"https:\/\/www.switch-science.com\/catalog\/4036\/\" target=\"_blank\" rel=\"noopener\">MLX90640\u642d\u8f09\u306e\u8d64\u5916\u7dda\u30a2\u30ec\u30a4\u30e2\u30b8\u30e5\u30fc\u30eb<\/a>\u3092ESP32\u306b\u3064\u306a\u3044\u3067\u71b1\u753b\u50cf\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u3001\u305d\u308c\u3092WebSocket\u3092\u4f7f\u3044\u30d6\u30e9\u30a6\u30b6\u304b\u3089\u71b1\u753b\u50cf\u3092\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u3067\u898b\u308c\u308b\u3088\u3046\u306b\u3057\u307e\u3057\u305f\u3002<\/p>\n<p>MLX90640\u306f32 x 24\u306e\u30bb\u30f3\u30b5\u30fc\u3092\u642d\u8f09\u3057\u3001I2C\u3067ESP32\u3068\u901a\u4fe1\u3092\u884c\u3046\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n<p><!--more--><\/p>\n<style>\n.hljs {max-height: 350px; overflow-y: auto;}<br \/>\n<\/style>\n<p><img decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/mlx90640-coffee.gif\" alt=\"\" width=\"600\" class=\"aligncenter size-full wp-image-5517\" \/>\n<\/p>\n<p>ESP32\u3068\u3064\u306a\u3044\u3067\u307f\u307e\u3057\u305f\u3002<br \/>\n1\u679a\u306e\u30c7\u30fc\u30bf\u53d6\u5f97\u3059\u308b\u306e\u306b\u7d040.5\u79d2\u7a0b\u5ea6\u304b\u304b\u308a\u307e\u3059\u3002<br \/>\n<img decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/mlx90640_board_640.jpg\" alt=\"\" width=\"400\" class=\"size-full wp-image-5497\" srcset=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/mlx90640_board_640.jpg 640w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/mlx90640_board_640-200x200.jpg 200w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/mlx90640_board_640-400x400.jpg 400w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/mlx90640_board_640-602x602.jpg 602w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/mlx90640_board_640-144x144.jpg 144w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/p>\n<p><\/p>\n<p>ESP32\u958b\u767a\u30dc\u30fc\u30c9\u306f\u300cHiLetgo ESP32 ESP-32S NodeMCU\u958b\u767a\u30dc\u30fc\u30c9\u300d\u3092\u4f7f\u7528\u3001WEB\u30b5\u30fc\u30d0\u306e\u305f\u3081<a href=\"https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer\">ESPAsyncWebServer<\/a>\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u4f7f\u3044\u307e\u3057\u305f\u3002<\/p>\n<p>ESPAsyncWebServer\u3001\u3088\u304f\u3067\u304d\u3066\u3044\u307e\u3059\u3002<br \/>\n\u7c21\u5358\u306b\u540c\u6642\u63a5\u7d9a\u3067\u304d\u308bWEB\u30b5\u30fc\u30d0\u3092\u4f5c\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3057\u305f\u3002\u307e\u305f\u3001WebSocket\u3059\u308b\u305f\u3081\u306b\u8ffd\u52a0\u306e\u30b5\u30fc\u30d0\u3084\u30dd\u30fc\u30c8\u3082\u5fc5\u8981\u3068\u3057\u307e\u305b\u3093\u3002<br \/>\n\u4fbf\u5229\u6a5f\u80fd\u3068\u3057\u3066SPIFFSEditor\u304c\u3064\u3044\u3066\u3044\u3066\u3001SPIFFS\u306b\u7f6e\u3044\u305f\u30d5\u30a1\u30a4\u30eb\u3092\u30d6\u30e9\u30a6\u30b6\u304b\u3089\/edit\u306b\u30a2\u30af\u30bb\u30b9\u3057\u3066\u8ffd\u52a0\u30fb\u7de8\u96c6\u3067\u304d\u307e\u3059\u3002<\/p>\n<p>IDE\u3068\u3057\u3066\u3001<a href=\"https:\/\/platformio.org\/\">PlatformIO<\/a>\u3092\u4f7f\u3044\u307e\u3057\u305f\u3002<br \/>\nESPAsyncWebServer\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067PlatformIO\u304c\u66f8\u304b\u308c\u3066\u308b\u3068\u3044\u3046\u306e\u3082\u3042\u308a\u307e\u3059\u304c\u3001\u6700\u521dArduino IDE\u3067MLX90640\u306e\u30b5\u30f3\u30d7\u30eb\u30bd\u30fc\u30b9\u3092\u52d5\u304b\u3057\u3066\u307f\u307e\u3057\u305f\u304c\u3001<a href=\"https:\/\/github.com\/melexis\/mlx90640-library\/issues\/13\">\u3053\u3053<\/a>\u3067\u66f8\u304b\u308c\u3066\u308b\u3088\u3046\u306a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u3046\u307e\u304f\u3044\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u305f\u3060\u3001\u3082\u3057\u304b\u3057\u305f\u3089\u53e4\u3044arduino-esp32\u3092\u4f7f\u3063\u3066\u305f\u306e\u304c\u539f\u56e0\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002<\/p>\n<p>\u30d5\u30a1\u30a4\u30eb\u306f\u4ee5\u4e0b\u306e\u69cb\u6210\u3067\u3059\u3002<\/p>\n<pre style=\"font-family: Consolas, 'Courier New', Courier, Monaco, monospace;\">\nplatformio.ini  \/\/ IDE\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\nsrc  \u2500 main.cpp\u3000\/\/ \u30e1\u30a4\u30f3\u30d7\u30ed\u30b0\u30e9\u30e0\nlib  \u252c MLX90640_API \u252c MLX90640_API.cpp \/\/ \u4ee5\u4e0b\u306e\u30d5\u30a1\u30a4\u30eb\u306fSparkFun\u306b\u3042\u308b\u30b5\u30f3\u30d7\u30eb\u304b\u3089\u53d6\u5f97\n     \u2502              \u2514 MLX90640_API.h\n     \u2514 MLX90640_I2C_Driver \u252c MLX90640_I2C_Driver.cpp\n                            \u2514 MLX90640_I2C_Driver.h    \ndata \u252c index.html  \/\/ SPIFFS\u306b\u7f6e\u304f\u9759\u7684\u30b3\u30f3\u30c6\u30f3\u30c4\n     \u251c app.js\n     \u251c app.css\n     \u251c ace.js.gz  \/\/ \u4ee5\u964d\u306e\u30d5\u30a1\u30a4\u30eb\u306fSPIFFSEditor\u4f7f\u7528\u6642\u306b\u4f7f\u3046\n     \u251c ext-searchbox.js.gz  \n     \u251c mode-css.js.gz\n     \u251c mode-html.js.gz\n     \u251c mode-javascript.js.gz\n     \u2514 worker-html.js.gz\n<\/pre>\n<p>\u30fbplatformio.ini<br \/>\nESPAsyncWebServer\u3092\u4f9d\u5b58\u30e9\u30a4\u30d6\u30e9\u30ea\u3068\u3057\u3066\u3044\u307e\u3059\u3002<br \/>\nOTA\u3067\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308b\u5834\u5408\u3001upload_port\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"ini\">[env:esp32dev]\nplatform = https:\/\/github.com\/platformio\/platform-espressif32.git\nboard = esp32dev\nframework = arduino\nmonitor_speed = 115200\n; upload_port = esp32.local\nlib_deps = https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer.git\n<\/code><\/pre>\n<p>\u30fbmain.cpp<br \/>\n\u57fa\u672c\u3001<a href=\"https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer\/tree\/master\/examples\/ESP_AsyncFSBrowser\">ESPAsyncWebServer<\/a>\u3068\u3001<a href=\"https:\/\/github.com\/sparkfun\/SparkFun_MLX90640_Arduino_Example\">SparkFun_MLX90640_Arduino_Example<\/a>\u306e\u30df\u30c3\u30af\u30b9\u3067\u3059\u3002<br \/>\n\u82e6\u52b4\u3057\u305f\u306e\u306fWebSocket\u3067\u306eESP32\u304b\u3089javascript\u3078\u306e\u30c7\u30fc\u30bf\u306e\u53d7\u3051\u6e21\u3057\u90e8\u5206\u3067\u3001\u30d0\u30a4\u30ca\u30ea\u30fc\u3067\u884c\u3044\u307e\u3057\u305f\u3002<\/p>\n<pre><code class=\"C\">#include &lt;Wire.h&gt;\n#include \"MLX90640_API.h\"\n#include \"MLX90640_I2C_Driver.h\"\n#include &lt;WiFi.h&gt;\n#include &lt;ESPmDNS.h&gt;\n#include &lt;ArduinoOTA.h&gt;\n\/\/ #include &lt;FS.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n#include &lt;SPIFFS.h&gt;\n#include &lt;SPIFFSEditor.h&gt;\n\n\/\/ WIFI\u8a2d\u5b9a\nconst char* ssid = \"*******\";\nconst char* password =  \"******\";\n\n\/\/ mDNS\nconst char * hostName = \"esp32\";\n\n\/\/ SPIFFSEditor\u306e\u8a8d\u8a3c\nconst char* http_username = \"admin\";\nconst char* http_password = \"admin\";\n\n\/\/ MLX90640\nconst byte MLX90640_address = 0x33; \/\/Default 7-bit unshifted address of the MLX90640\n#define TA_SHIFT 8 \/\/Default shift for MLX90640 in open air\nfloat mlx90640To[768];\nparamsMLX90640 mlx90640;\n\n\/\/ SKETCH BEGIN\nAsyncWebServer server(80);\nAsyncWebSocket ws(\"\/ws\");\n\nvoid onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){\n  if(type == WS_EVT_CONNECT){\n    Serial.printf(\"ws[%s][%u] connect\\n\", server-&gt;url(), client-&gt;id());\n  } else if(type == WS_EVT_DISCONNECT){\n    Serial.printf(\"ws[%s][%u] disconnect\\n\", server-&gt;url(), client-&gt;id());\n  } else if(type == WS_EVT_ERROR){\n    Serial.printf(\"ws[%s][%u] error(%u): %s\\n\", server-&gt;url(), client-&gt;id(), *((uint16_t*)arg), (char*)data);\n  }\n}\n\n\/\/Returns true if the MLX90640 is detected on the I2C bus\nboolean isConnected()\n{\n  Wire.beginTransmission((uint8_t)MLX90640_address);\n  if (Wire.endTransmission() != 0)\n    return (false); \/\/Sensor did not ACK\n  return (true);\n}\n\nvoid setUpMLX90640 () {\n  if (isConnected() == false)\n  {\n    Serial.println(\"MLX90640 not detected at default I2C address. Please check wiring. Freezing.\");\n    while (1);\n  }\n\n  \/\/Get device parameters - We only have to do this once\n  int status;\n  uint16_t eeMLX90640[832];\n  status = MLX90640_DumpEE(MLX90640_address, eeMLX90640);\n  if (status != 0)\n    Serial.println(\"Failed to load system parameters\");\n\n  status = MLX90640_ExtractParameters(eeMLX90640, &amp;mlx90640);\n  if (status != 0)\n    Serial.println(\"Parameter extraction failed\");\n    Serial.println(status);\n\n  \/\/Once params are extracted, we can release eeMLX90640 array\n\n  \/\/MLX90640_SetRefreshRate(MLX90640_address, 0x02); \/\/Set rate to 2Hz\n  MLX90640_SetRefreshRate(MLX90640_address, 0x03); \/\/Set rate to 4Hz\n  \/\/MLX90640_SetRefreshRate(MLX90640_address, 0x07); \/\/Set rate to 64Hz  \n}\n\nvoid setUpOTA() {\n  ArduinoOTA.onStart([]() { Serial.println(\"Update Start\"); });\n  ArduinoOTA.onEnd([]() { Serial.println(\"Update End\"); });\n  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {\n    Serial.printf(\"Progress: %u%%\\r\", (progress \/ (total \/ 100)));\n  });\n  ArduinoOTA.onError([](ota_error_t error) {\n    Serial.println(\"OTA ERROR\");\n  });\n  ArduinoOTA.setHostname(hostName);\n  ArduinoOTA.begin();\n}\n\nvoid setup(){\n  Wire.begin();\n  Serial.begin(115200);\n  Serial.setDebugOutput(true);\n  WiFi.begin(ssid, password);\n\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(1000);\n    Serial.println(\"Connecting to WiFi..\");\n  }\n  Serial.println(\"WiFi connected!\");\n\n  \/\/OTA\n  setUpOTA();\n\n  \/\/ mDNS\n  if (!MDNS.begin(hostName)) {\n      Serial.println(\"Error setting up MDNS responder!\");\n      while(1){\n          delay(1000);\n      }\n  }\n\n  SPIFFS.begin(true);\n\n  ws.onEvent(onWsEvent);\n  server.addHandler(&amp;ws);\n\n  \/\/ SPIFFS\u306b\u3042\u308b\u30d5\u30a1\u30a4\u30eb\u3092\u30d6\u30e9\u30a6\u30b6\u3067\/edit\u304b\u3089\u7de8\u96c6\u3067\u304d\u308b\n  server.addHandler(new SPIFFSEditor(SPIFFS,http_username,http_password));\n\n  \/\/ SPIFFS\n  server.serveStatic(\"\/\", SPIFFS, \"\/\").setDefaultFile(\"index.htm\");\n\n  server.onNotFound([](AsyncWebServerRequest *request){\n    Serial.printf(\"NOT_FOUND: \");\n    request-&gt;send(404);\n  });\n  server.begin();\n\n  \/\/ MLX90640\u306e\u521d\u671f\u8a2d\u5b9a\n  setUpMLX90640();\n}\n\nvoid loop(){\n  ArduinoOTA.handle();\n\n  if (ws.count() &gt; 0) {\n    \/\/ WebSocket\u63a5\u7d9a\u4e2d\u306e\u307f\u6e29\u5ea6\u53d6\u5f97\u3059\u308b\n    long startTime = millis();\n    for (byte x = 0 ; x &lt; 2 ; x++)\n    {\n      uint16_t mlx90640Frame[834];\n      MLX90640_GetFrameData(MLX90640_address, mlx90640Frame);\n      \/\/ float vdd = MLX90640_GetVdd(mlx90640Frame, &amp;mlx90640);\n      float Ta = MLX90640_GetTa(mlx90640Frame, &amp;mlx90640);\n\n      float tr = Ta - TA_SHIFT; \/\/Reflected temperature based on the sensor ambient temperature\n      float emissivity = 0.95;\n\n      MLX90640_CalculateTo(mlx90640Frame, &amp;mlx90640, emissivity, tr, mlx90640To);\n    }\n    long calculatedTime = millis();\n\n    AsyncWebSocketMessageBuffer * buffer = ws.makeBuffer((uint8_t *)&amp;mlx90640To, sizeof(mlx90640To)); \n    ws.binaryAll(buffer);   \/\/ \u30d0\u30a4\u30ca\u30ea\u30fc\uff08uint8_t\u306e\u914d\u5217\uff09\u3067\u5168\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306b\u9001\u4fe1\n\n    long finishedTime = millis();\n    Serial.printf(\"calculated secs:%.2f, finished secs:%.2f\\n\", (float)(calculatedTime - startTime)\/1000, (float)(finishedTime - startTime)\/1000);  \n  }\n}\n\n<\/code><\/pre>\n<p>\u30fbMLX90640_I2C_Driver.cpp<br \/>\nSparkFun\u306b\u3042\u308b<a href=\"https:\/\/github.com\/sparkfun\/SparkFun_MLX90640_Arduino_Example\">\u30b5\u30f3\u30d7\u30eb<\/a>\u306e\u307e\u307e\u3060\u3068ESP32\u306e\u5834\u5408\u3001\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002<br \/>\nArduino.h\u3092\u30a4\u30f3\u30af\u30eb\u30fc\u30c9\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n<pre><code class=\"C\">#include&lt;Arduino.h&gt;\n<\/code><\/pre>\n<p>\u30fbindex.htm<\/p>\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;meta http-equiv=\"Content-type\" content=\"text\/html; charset=utf-8\"&gt;\n    &lt;meta name=\"viewport\" content=\"width=350,initial-scale=0.5\"&gt;\n    &lt;title&gt;\u8d64\u5916\u7dda\u30a2\u30ec\u30a4\u30ab\u30e1\u30e9\u3000MLX90640&lt;\/title&gt;\n    &lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"app.css\" &gt;\n  &lt;\/head&gt;\n  &lt;body id=\"body\" onload=\"onBodyLoad()\"&gt;\n    &lt;div id=\"container\"&gt;\n      &lt;canvas id=\"canvas\" width=\"32\" height=\"24\"&gt;&lt;\/canvas&gt;\n      &lt;div id=\"scale\"&gt;&lt;\/div&gt;  \n      &lt;div id=\"scale-divisions\"&gt;\n        &lt;div id=\"min-tmp-division\"&gt;&lt;span id=\"min-down\" class=\"divisionBtn\"&gt;&#x25c0;&lt;\/span&gt;&lt;span id=\"min-tmp\"&gt;&lt;\/span&gt;&lt;span id=\"min-up\" class=\"divisionBtn\"&gt;&#x25b6;&lt;\/span&gt;&lt;\/div&gt;\n        &lt;div id=\"max-tmp-division\"&gt;&lt;span id=\"max-down\" class=\"divisionBtn\"&gt;&#x25c0;&lt;\/span&gt;&lt;span id=\"max-tmp\"&gt;&lt;\/span&gt;&lt;span id=\"max-up\" class=\"divisionBtn\"&gt;&#x25b6;&lt;\/span&gt;&lt;\/div&gt;\n      &lt;\/div&gt;\n      &lt;div id=\"messages\"&gt;&lt;\/div&gt;\n    &lt;\/div&gt;\n    &lt;script src=\"app.js\"&gt;&lt;\/script&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<p>\u30fbapp.css<\/p>\n<pre><code class=\"css\">body {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    background-color: black;\n    color: #ffffff;\n    font-size: 12px;\n  }\n  #canvas {\n          background: #666;\n          width: 640px;\n          height: 480px;\n  }\n  #scale, #scale-divisions {\n    width: 100%;\n    height: 24px;\n  }\n  #scale-divisions {\n    position: relative;\n  }\n  #min-tmp-division {\n    position: absolute;\n    left: -20px;\n  }\n  #max-tmp-division {\n    position: absolute;\n    right: -20px;\n  }\n  .division {\n    position: absolute;\n  }\n  #scale {\n    display: flex;\n  }\n  #scale span {\n    display: block;\n    width: 1%;\n    height: 23px;\n  }\n  #messages {\n    overflow-y: auto;\n  }\n  .divisionBtn {\n    cursor: pointer;\n  }\n  .divisionBtn:hover{\n    color: #99b2ce;\n  }\n  @media only screen and (max-device-width: 480px) {\n    body {\n      font-size:24px;\n    }\n    #messages {\n      margin-top:20px;\n    }\n  }\n<\/code><\/pre>\n<p>\u30fbapp.js<\/p>\n<pre><code>const ge = (s) =&gt; { return document.getElementById(s);}\nconst ce = (s) =&gt; { return document.createElement(s);}\nconst gc = (s) =&gt; { return document.getElementsByClassName(s);}\nconst addMessage = (m) =&gt; {\n  \/\/ \u30e1\u30c3\u30bb\u30fc\u30b8\u8868\u793a\n  \/\/ console.log(m);\n  const msg = ce(\"div\");\n  msg.innerText = m;\n  ge(\"messages\").appendChild(msg);\n  ge(\"messages\").append\n}\nskt = {\n  ws: null,\n  start: function() {\n    \/\/ WebSocket\u3092\u958b\u59cb\n    ws = ws = new WebSocket('ws:\/\/'+document.location.host+'\/ws',['arduino']);\n    ws.binaryType = \"arraybuffer\";\n    ws.onopen = (e) =&gt; {\n      addMessage(\"Connected\");\n    };\n    ws.onclose = (e) =&gt; {\n      addMessage(\"Disconnected\");\n    };\n    ws.onerror = (e) =&gt; {\n      console.log(\"ws error\", e);\n      addMessage(\"Error\");\n    };\n    ws.onmessage = (e)=&gt;{\n      if(e.data instanceof ArrayBuffer){\n        \/\/ \u30d0\u30a4\u30ca\u30ea\u30fc\u30c7\u30fc\u30bf\u306e\u5834\u5408\n        this.parseTemparatures(e.data);\n      } else {\n        \/\/ \u30c6\u30ad\u30b9\u30c8\u30c7\u30fc\u30bf\u306e\u5834\u5408\n        addMessage(e.data);\n      }\n    };\n  },\n  parseTemparatures: (data) =&gt; {\n    \/\/ Uint8Array\u306b\u30bb\u30c3\u30c8\u3055\u308c\u305f4\u30d0\u30a4\u30c8\u306efloat\u306e\u914d\u5217\u3092Float32Array\u306e\u578b\u4ed8\u304d\u914d\u5217\u306b\u30bb\u30c3\u30c8\u3057\u3001\u63cf\u753b\u3057\u307e\u3059\u3002\n    const dv = new DataView(data);\n    const byteSize = 4;\n    const tmps = new Float32Array(data.byteLength \/ byteSize);          \n    for (let i = 0; i&lt;tmps.length; i++) {\n      tmps[i] = dv.getFloat32(i*byteSize, true);\n    }\n    cv.draw(tmps);          \n  }\n};\nconst HSVtoRGB = (h, s, v) =&gt; {\n  \/\/ HSV\u304b\u3089RGB\u306b\u5909\u63db \u30d1\u30e9\u30e1\u30fc\u30bfh,s,v\u306f0\u4ee5\u4e0a1\u4ee5\u4e0b\n  let r, g, b, i, f, p, q, t;\n  i = Math.floor(h * 6);\n  f = h * 6 - i;\n  p = v * (1 - s);\n  q = v * (1 - f * s);\n  t = v * (1 - (1 - f) * s);\n  switch (i % 6) {\n      case 0: r = v, g = t, b = p; break;\n      case 1: r = q, g = v, b = p; break;\n      case 2: r = p, g = v, b = t; break;\n      case 3: r = p, g = q, b = v; break;\n      case 4: r = t, g = p, b = v; break;\n      case 5: r = v, g = p, b = q; break;\n  }\n  return {\n      r: Math.round(r * 255),\n      g: Math.round(g * 255),\n      b: Math.round(b * 255)\n  };\n}\n\nconst rgb = {\n    min: 20,  \/\/ \u8868\u793a\u3059\u308b\u6700\u4f4e\u6e29\u5ea6\n    max: 35,  \/\/ \u8868\u793a\u3059\u308b\u6700\u9ad8\u6e29\u5ea6\n    get: function(tmp) {\n        \/\/ \u6e29\u5ea6\u304b\u3089\u8272\uff08RGB\uff09\u3092\u53d6\u5f97\n        let rate = 1 - (tmp - this.min)\/(this.max - this.min);\n        if (rate &lt; 0) {\n            rate = 0;\n        } else if (rate &gt; 1) {\n            rate = 1;\n        }\n        \/\/ const h = 0.7*rate;\n        const h = (Math.tanh(rate*2 - 1.5) + 1)\/2 - 0.04; \/\/ \u9069\u5f53\n        return HSVtoRGB(h, 1, 1);\n    }\n};\n\nconst cv = {\n  canvas: null,\n  content: null,\n  imageData: null,\n  createCanvas: function() {\n    \/\/ Canvas\u3092\u4f5c\u6210\n    this.canvas = ge('canvas');\n    this.context = this.canvas.getContext('2d');\n    this.imageData = this.context.createImageData(32, 24);\n  },\n  createScale: function(){\n    \/\/ \u30b9\u30b1\u30fc\u30eb\u3092\u4f5c\u6210\n    const scale = ge('scale');\n    let color, t, span;\n    for (let i=0; i &lt; 100; i++) {\n      t = i * (rgb.max - rgb.min)\/100 + rgb.min;\n      span = ce('span');\n      color = rgb.get(t);\n      span.style.backgroundColor = span.style.color = 'rgb('+color.r+','+color.g+','+color.b+')';\n      scale.appendChild(span);\n    }\n    this.createDivisions();\n  },\n  createDivisions: () =&gt; {\n    \/\/ \u76ee\u76db\u308a\u4f5c\u6210\n    ge(\"min-tmp\").textContent = rgb.min;\n    ge(\"max-tmp\").textContent = rgb.max;\n\n    var scaleDivisions = ge('scale-divisions');\n    const divisions = gc('division');\n    while(divisions.length &gt; 0){\n      scaleDivisions.removeChild(divisions[0]);\n    }\n    let div;\n    for (let temp = rgb.min+5; temp &lt; rgb.max; temp+=5) {\n      div = ce('div');\n      div.innerText = temp;\n      div.classList.add(\"division\");\n      div.style.left = 640*(temp - rgb.min)\/(rgb.max - rgb.min)-7 + 'px';\n      scaleDivisions.appendChild(div);\n    }\n  },\n  draw: function(tmps) {\n    \/\/ \u63cf\u753b\n    const data = this.imageData.data; \/\/ RGBA \u306e\u9806\u756a\u306e\u30c7\u30fc\u30bf\u3092\u542b\u3093\u3060 1\u6b21\u5143\u914d\u5217\u3002\u305d\u308c\u305e\u308c\u306e\u5024\u306f 0 \uff5e 255 \u306e\u7bc4\u56f2\u3068\u306a\u308a\u307e\u3059\u3002\n    if (data.length\/4 != tmps.length) {\n      alert(\u306a\u306b\u304b\u304a\u304b\u3057\u3044\u3067\u3059);\n      return;\n    }\n    let tmp, color, j, mirror;\n    const maxValue = 255;\n    for (let i = 0; i &lt; tmps.length; i++) {\n      if (false) {\n        j = 4 * i;\n      } else {\n         \/\/ \u5de6\u53f3\u53cd\u8ee2\u3055\u305b\u308b\n        mirror = (31-i%32) + parseInt(i\/32)*32;\n        j = 4 * mirror;\n      }\n      tmp = tmps[i];\n      color = rgb.get(tmp);\n      data[j] = color.r;\n      data[j+1] = color.g;\n      data[j+2] = color.b;\n      data[j+3] = maxValue;\n    }\n    this.context.putImageData(this.imageData, 0, 0);\n  }\n};\n\nconst divisionBtns = gc('divisionBtn');\nfor (let i=0; i &lt; divisionBtns.length; i++){\n  divisionBtns[i].addEventListener('click', function() {\n    \/\/ \u76ee\u76db\u308a\u5909\u66f4\n    const d = 5; \/\/ \u76ee\u76db\u308a\u306e\u9593\u9694\n    switch(this.id) {\n      case 'min-down':\n        if (rgb.min &gt;= 5) rgb.min -= d;\n        break;\n      case 'min-up':\n        if (rgb.min &lt;= rgb.max-2*d) rgb.min += d;\n        break;\n        case 'max-down':\n        if (rgb.min &lt;= rgb.max-2*d) rgb.max -= d;\n        break;\n      case 'max-up':\n        if (rgb.max &lt;= 90) rgb.max += d;\n        break;\n    }\n    cv.createDivisions();\n  });      \n}\n\nlet onBodyLoad = function(){\n  cv.createScale();\n  skt.start();\n  cv.createCanvas();\n}\n<\/code><\/pre>\n<p>\u6b21\u56de\u3001\u3053\u308c\u3092\u4f7f\u3063\u3066\u30c7\u30a3\u30fc\u30d7\u30e9\u30fc\u30cb\u30f3\u30b0\u3092\u884c\u3044\u305f\u3044\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n<a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-facebook nolightbox\" data-provider=\"facebook\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Facebook\" href=\"https:\/\/www.facebook.com\/sharer.php?u=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5479&#038;t=%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%82%A2%E3%83%AC%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%80%8CMLX90640%E3%80%8D%E3%82%92ESP32%E3%81%AB%E3%81%A4%E3%81%AA%E3%81%84%E3%81%A7WebSocket%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F&#038;s=100&#038;p&#091;url&#093;=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5479&#038;p&#091;images&#093;&#091;0&#093;=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F01%2Fmlx90640-coffee.gif&#038;p&#091;title&#093;=%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%82%A2%E3%83%AC%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%80%8CMLX90640%E3%80%8D%E3%82%92ESP32%E3%81%AB%E3%81%A4%E3%81%AA%E3%81%84%E3%81%A7WebSocket%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"Facebook\" title=\"Share on Facebook\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/facebook.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-twitter nolightbox\" data-provider=\"twitter\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Twitter\" href=\"http:\/\/twitter.com\/share?url=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5479&#038;text=%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%82%A2%E3%83%AC%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%80%8CMLX90640%E3%80%8D%E3%82%92ESP32%E3%81%AB%E3%81%A4%E3%81%AA%E3%81%84%E3%81%A7WebSocket%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"twitter\" title=\"Share on Twitter\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/twitter.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-linkedin nolightbox\" data-provider=\"linkedin\" target=\"_blank\" rel=\"nofollow\" title=\"Share on Linkedin\" href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5479&#038;title=%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%82%A2%E3%83%AC%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%80%8CMLX90640%E3%80%8D%E3%82%92ESP32%E3%81%AB%E3%81%A4%E3%81%AA%E3%81%84%E3%81%A7WebSocket%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"linkedin\" title=\"Share on Linkedin\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/linkedin.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-tumblr nolightbox\" data-provider=\"tumblr\" target=\"_blank\" rel=\"nofollow\" title=\"Share on tumblr\" href=\"https:\/\/tumblr.com\/share?s=&#038;v=3&#038;t=%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%82%A2%E3%83%AC%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%80%8CMLX90640%E3%80%8D%E3%82%92ESP32%E3%81%AB%E3%81%A4%E3%81%AA%E3%81%84%E3%81%A7WebSocket%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F&#038;u=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5479\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px;margin-right:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"tumblr\" title=\"Share on tumblr\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/tumblr.png\" \/><\/a><a class=\"synved-social-button synved-social-button-share synved-social-size-24 synved-social-resolution-single synved-social-provider-mail nolightbox\" data-provider=\"mail\" rel=\"nofollow\" title=\"Share by email\" href=\"mailto:?subject=%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%82%A2%E3%83%AC%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%80%8CMLX90640%E3%80%8D%E3%82%92ESP32%E3%81%AB%E3%81%A4%E3%81%AA%E3%81%84%E3%81%A7WebSocket%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F&#038;body=%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%99%E3%82%8B%EF%BC%9A:%20https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5479\" style=\"font-size: 0px;width:24px;height:24px;margin:0;margin-bottom:5px\"><img loading=\"lazy\" decoding=\"async\" alt=\"mail\" title=\"Share by email\" class=\"synved-share-image synved-social-image synved-social-image-share\" width=\"24\" height=\"24\" style=\"display: inline;width:24px;height:24px;margin: 0;padding: 0;border: none;box-shadow: none\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/plugins\/social-media-feather\/synved-social\/image\/social\/regular\/48x48\/mail.png\" \/><\/a>","protected":false},"excerpt":{"rendered":"<p>MLX90640\u642d\u8f09\u306e\u8d64\u5916\u7dda\u30a2\u30ec\u30a4\u30e2\u30b8\u30e5\u30fc\u30eb\u3092ESP32\u306b\u3064\u306a\u3044\u3067\u71b1\u753b\u50cf\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u3001\u305d\u308c\u3092WebSocket\u3092\u4f7f\u3044\u30d6\u30e9\u30a6\u30b6\u304b\u3089\u71b1\u753b\u50cf\u3092\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u3067\u898b\u308c\u308b\u3088\u3046\u306b\u3057\u307e\u3057\u305f\u3002 MLX90640\u306f32 x 24\u306e\u30bb\u30f3\u30b5\u30fc\u3092\u642d [&hellip;]<\/p>\n","protected":false},"author":25,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[172,1],"tags":[],"class_list":["post-5479","post","type-post","status-publish","format-standard","hentry","category-iot","category-1"],"_links":{"self":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/5479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/users\/25"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/comments?post=5479"}],"version-history":[{"count":39,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/5479\/revisions"}],"predecessor-version":[{"id":7750,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/5479\/revisions\/7750"}],"wp:attachment":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/media?parent=5479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/categories?post=5479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/tags?post=5479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}