{"id":5523,"date":"2019-02-01T12:50:05","date_gmt":"2019-02-01T03:50:05","guid":{"rendered":"https:\/\/www.lancard.com\/blog\/?p=5523"},"modified":"2025-03-12T11:26:05","modified_gmt":"2025-03-12T02:26:05","slug":"esp32%e3%81%a7%e3%83%87%e3%82%a3%e3%83%bc%e3%83%97%e3%83%a9%e3%83%bc%e3%83%8b%e3%83%b3%e3%82%b0","status":"publish","type":"post","link":"https:\/\/www.lancard.com\/blog\/2019\/02\/01\/esp32%e3%81%a7%e3%83%87%e3%82%a3%e3%83%bc%e3%83%97%e3%83%a9%e3%83%bc%e3%83%8b%e3%83%b3%e3%82%b0\/","title":{"rendered":"ESP32\u3067\u30c7\u30a3\u30fc\u30d7\u30e9\u30fc\u30cb\u30f3\u30b0"},"content":{"rendered":"<p><a href=\"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\/\">\u5148\u65e5\u4f5c\u3063\u305f\u71b1\u753b\u50cf\u3092\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u3067\u898b\u308c\u308b\u30b7\u30b9\u30c6\u30e0<\/a>\u3092\u6539\u9020\u3057\u3001\u30c7\u30a3\u30fc\u30d7\u30e9\u30fc\u30cb\u30f3\u30b0\u3057\u3066\u307f\u307e\u3057\u305f\u3002<br \/>\n\u30b8\u30e3\u30f3\u30b1\u30f3\u306e\uff13\u3064\u306e\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u3092\u3001<a href=\"https:\/\/www.switch-science.com\/catalog\/4036\/\">\u8d64\u5916\u7dda\u30a2\u30ec\u30a4\u30e2\u30b8\u30e5\u30fc\u30eb<\/a>\u304b\u3089\u306e\u5165\u529b\u30c7\u30fc\u30bf\u3092\u3082\u3068\u306b\u63a8\u8ad6\u3057\u307e\u3059\u3002<br \/>\n\u30b8\u30e3\u30f3\u30b1\u30f3\u306e\u753b\u50cf\u30c7\u30fc\u30bf\u3092\u4f7f\u3044\u30c7\u30a3\u30fc\u30d7\u30e9\u30fc\u30cb\u30f3\u30b0\u3059\u308b\u3001\u3068\u3044\u3046\u30a2\u30a4\u30c7\u30a2\u306f\u96d1\u8a8cInterface1\u6708\u53f7\u306e\u8a18\u4e8b\u306e\u307e\u306d\u3092\u3055\u305b\u3066\u3044\u305f\u3060\u304d\u307e\u3057\u305f\u3002\u4ed6\u306b\u3082\u3044\u308d\u3044\u308d\u3068\u53c2\u8003\u306b\u3055\u305b\u3066\u3044\u305f\u3060\u304d\u307e\u3057\u305f\u3002<br \/>\n\u306a\u304a\u3001\u96d1\u8a8cInterface1\u6708\u53f7\u306e\u8a18\u4e8b\u3067\u306f\u30bd\u30cb\u30fc\u306eSPRESENSE\u30dc\u30fc\u30c9\u3001\u304a\u3088\u3073\u901a\u5e38\u306e\u30ab\u30e1\u30e9\u30dc\u30fc\u30c9\u3092\u4f7f\u3063\u3066\u884c\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n<p>\u30c7\u30a3\u30fc\u30d7\u30e9\u30fc\u30cb\u30f3\u30b0\u306e\u30c4\u30fc\u30eb\u3068\u3057\u3066Neural Network Console(NNC)\u306e\u30af\u30e9\u30a6\u30c9\u3092\u4f7f\u3044\u5b66\u7fd2\u3055\u305b\u307e\u3057\u305f\u3002<br \/>\n\u5b66\u7fd2\u6e08\u307f\u30e2\u30c7\u30eb\u3092NNP\u30d5\u30a1\u30a4\u30eb\u3068\u3057\u3066\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u3001NNP\u30d5\u30a1\u30a4\u30eb\u3092C\u8a00\u8a9e\u30d5\u30a1\u30a4\u30eb\u306b\u5909\u63db\u5f8c\u3001ESP32\u306b\u7d44\u307f\u8fbc\u307f\u307e\u3057\u305f\u3002<br \/>\n\u30102019\/02\/04 \u8ffd\u8a18\u3011NNP\u4ee5\u5916\u306bNNB\uff08C\u30e9\u30f3\u30bf\u30a4\u30e0\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\uff09\u3067\u3082ESP32\u306b\u7d44\u307f\u8fbc\u3080\u3053\u3068\u304c\u3067\u304d\u308b\u3053\u3068\u3092\u78ba\u8a8d\u3057\u307e\u3057\u305f\u306e\u3067\u3001\u305d\u308c\u3082\u8ffd\u8a18\u3057\u307e\u3057\u305f\u3002<\/p>\n<p><!--more--><\/p>\n<style>\n.hljs {max-height: 350px; overflow-y: scroll;}<br \/>\n<\/style>\n<p><img decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/01\/jyanken.gif\" alt=\"\" width=\"600\" class=\"aligncenter size-full wp-image-5524\" \/><\/p>\n<p>\u4ee5\u4e0b\u306e\u30b9\u30c6\u30c3\u30d7\u3092\u884c\u3044\u307e\u3057\u305f\u3002<\/p>\n<ol>\n<li>WebSocket\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3067\u30c7\u30fc\u30bf\u53ce\u96c6<\/li>\n<li>\u30d6\u30e9\u30a6\u30b6\u3067\u53ce\u96c6\u3057\u305f\u30c7\u30fc\u30bf\u306e\u78ba\u8a8d<\/li>\n<li>\u30c7\u30fc\u30bf\u3092\u6c34\u5897\u3057\u3059\u308b\uff08Data Augmentation\uff09<\/li>\n<li>\u30c7\u30fc\u30bf\u5909\u63db\u3057CSV\u30d5\u30a1\u30a4\u30eb\u4f5c\u6210<\/li>\n<li>NNC(\u30af\u30e9\u30a6\u30c9)\u3067\u5b66\u7fd2<\/li>\n<li>\u5b66\u7fd2\u6e08\u307f\u30e2\u30c7\u30eb\u3092ESP32\u306b\u5b9f\u88c5<\/li>\n<\/ol>\n<p>\u6700\u7d42\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u69cb\u6210\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     \u251c MLX90640_I2C_Driver \u252c MLX90640_I2C_Driver.cpp\n     \u2502                     \u2514 MLX90640_I2C_Driver.h   \n     \u251c MainRuntime_inference \u252c MainRuntime_inference.c \/\/ \u63a8\u8ad6\u3059\u308b\u30d7\u30ed\u30b0\u30e9\u30e0\u3001NNP\u304b\u3089\u5909\u63db\uff08NNP\u3092\u4f7f\u3046\u5834\u5408\uff09\n     \u2502                       \u2514 MainRuntime_inference.h  \n     \u2514 MainRuntime_parameters\u252c MainRuntime_parameters.c \/\/ \u91cd\u307f\u306e\u914d\u5217\u3001NNP\u304b\u3089\u5909\u63db\uff08NNP\u3092\u4f7f\u3046\u5834\u5408\uff09\n                             \u2514 MainRuntime_parameters.h  \ndata \u252c index.html  \/\/ SPIFFS\u306b\u7f6e\u304f\u9759\u7684\u30b3\u30f3\u30c6\u30f3\u30c4\n     \u251c result.nnb  \/\/ \uff08NNB\u3092\u4f7f\u3046\u5834\u5408\uff09\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\nwork \u252c image_data_generator.py  \/\/ WebSocket\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3067\u30c7\u30fc\u30bf\u53ce\u96c6\u3059\u308b\u30d7\u30ed\u30b0\u30e9\u30e0\n     \u251c check.htm  \/\/ \u4f5c\u6210\u3057\u305f\u30c7\u30fc\u30bf\u3092\u78ba\u8a8d\u3059\u308bHTML\n     \u251c image_data_generator.py  \/\/ \u30c7\u30fc\u30bf\u3092\u6c34\u5897\u3057\uff08Data Augmentation\uff09\u3059\u308b\u30d7\u30ed\u30b0\u30e9\u30e0\n     \u2514 make_csv.py  \/\/ \u30c7\u30fc\u30bf\u5909\u63db\u3057CSV\u30d5\u30a1\u30a4\u30eb\u4f5c\u6210\u3059\u308b\u30d7\u30ed\u30b0\u30e9\u30e0\n\n\n<\/pre>\n<h5>WebSocket\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3067\u30c7\u30fc\u30bf\u53ce\u96c6<\/h5>\n<p>\u30c7\u30fc\u30bf\u53ce\u96c6\u306e\u3084\u308a\u65b9\u306f\u3001\u96d1\u8a8cInterface1\u6708\u53f7\u3068\u540c\u69d8\u306b\u9023\u5199\u3067\u30b8\u30e3\u30f3\u30b1\u30f3\u306e\u540c\u3058\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u3092\u30dd\u30fc\u30ba\u3092\u5909\u3048\u3066\u64ae\u5f71\u3057\u3001\u884c\u3044\u307e\u3057\u305f\u3002<br \/>\n\u30c7\u30fc\u30bf\u30d5\u30a1\u30a4\u30eb\u306e\u66f8\u304d\u51fa\u3057\u306f\u3001Python\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u4f5c\u6210\u3057\u305fWebSocket\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3067\u884c\u3044\u307e\u3057\u305f\u3002\u30d6\u30e9\u30a6\u30b6\u3067\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u3092\u78ba\u8a8d\u3057\u3064\u3064\u3001\u3082\u3046\u4e00\u3064\u306eWebSocket\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3067\u63a5\u7d9a\u3057\u3066\u30c7\u30fc\u30bf\u306e\u53ce\u96c6\u30fb\u66f8\u304d\u51fa\u3057\u3092\u3057\u307e\u3059\u3002<\/p>\n<p>\u5b9f\u884c\u6642\u306e\u5f15\u6570\u3067\u3001\u7d50\u679c\u306e\u30e9\u30d9\u30eb\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002<br \/>\n\u300c\u30b0\u30fc\u300d\u30920\u3001\u300c\u30c1\u30e7\u30ad\u300d\u30921\u3001\u300c\u30d1\u30fc\u300d\u30922\u3068\u3057\u307e\u3059\u3002<br \/>\n\u4ee5\u4e0b\u3092\u5b9f\u884c\u3057\u3001\u305d\u306e\u9593\u30ab\u30e1\u30e9\u306e\u524d\u3067\u300c\u30b0\u30fc\u300d\u306e\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u3092\u3001\u30dd\u30fc\u30ba\u3092\u5909\u3048\u3066\u30c7\u30fc\u30bf\u53ce\u96c6\u3057\u307e\u3059\u3002<br \/>\n\u5404\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u6bce\u306b500\u679a\u3001\u8a081500\u679a\u64ae\u5f71\u3057\u307e\u3057\u305f\u3002<br \/>\n0.5\u79d2\u306b\uff11\u679a\u64ae\u308c\u308b\u306e\u3067\u3001500&#215;0.5=250\u79d2 \u306e\uff13\u30bb\u30c3\u30c8\u306710\u5206\u3061\u3087\u3063\u3068\u304b\u304b\u308a\u307e\u3057\u305f\u3002<br \/>\n\u30c7\u30fc\u30bf\u306f\u3001\u3042\u3068\u3067\u30d6\u30e9\u30a6\u30b6\u3067\u78ba\u8a8d\u3059\u308b\u305f\u3081JSON\u30c7\u30fc\u30bf\u3067\u51fa\u529b\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"bash\">$ python collect_data.py 0\n<\/code><\/pre>\n<p>\u30fbcollect_data.py<\/p>\n<pre><code class=\"python\">import websocket\nimport struct\nfrom datetime import datetime\nimport json\nimport sys\n\nargs = sys.argv\nif len(args) &gt;= 2:\n    y = int(args[1])\nelse:\n    y = 9\n\npath = \".\/temperature_%s.json\" % datetime.now().strftime(\"%Y%m%d%H%M%S\")\ncounter = 0\n\ndef on_message(ws, message):\n    global counter\n    tmps = [chunk[0] for chunk in struct.iter_unpack('&lt;f', message)]\n    data= [datetime.now().timestamp(), y, tmps]\n\n    if counter%50 == 0:\n        print('counter: %s' % counter)\n\n    counter += 1\n    with open(path, mode='a') as f:\n        f.write(json.dumps(data) + \",\\n\")\n\ndef on_error(ws, error):\n    print(error)\n\ndef on_close(ws):\n    print(\"### closed ###\")\n\ndef on_open(ws):\n    print(\"### open ###\")\n\nif __name__ == \"__main__\":\n    # websocket.enableTrace(True)\n    ws = websocket.WebSocketApp(\"ws:\/\/esp32.local\/ws\",\n                              on_message = on_message,\n                              on_error = on_error,\n                              on_close = on_close)\n    ws.on_open = on_open\n    ws.run_forever()\n<\/code><\/pre>\n<h5>\u30d6\u30e9\u30a6\u30b6\u3067\u53ce\u96c6\u3057\u305f\u30c7\u30fc\u30bf\u306e\u78ba\u8a8d<\/h5>\n<p>\u4e0a\u8a18\u3067\u4f5c\u6210\u3057\u305f\u30c7\u30fc\u30bf\u30d5\u30a1\u30a4\u30eb3\u3064\u3092\u7d50\u5408\u3057\u307e\u3059\u3002\u305d\u306e\u969b\u3001\u30d5\u30a1\u30a4\u30eb\u306e\u982d\u306b&#8221;[&#8220;\u3092\u633f\u5165\u3001\u30d5\u30a1\u30a4\u30eb\u306e\u6700\u5f8c\u306e&#8221;,&#8221;\u3092&#8221;]&#8221;\u306b\u7f6e\u63db\u3057\u307e\u3059\u3002\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u304b\u3093\u3058\u306e\u30b3\u30de\u30f3\u30c9\u3092\u5b9f\u884c\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"bash\">$ cat temperature_201901* | sed -e '$s\/.$\/]\/' -e '1s\/^\/[\/' &gt; temperature_201901.json\n<\/code><\/pre>\n<p>\u53ce\u96c6\u3057\u305f\u30c7\u30fc\u30bf\u3092\u30d6\u30e9\u30a6\u30b6\u3067\u78ba\u8a8d\u3057\u307e\u3059\u3002<br \/>\n\u4ee5\u4e0b\u306e\u3088\u3046\u306aHTML\u30d5\u30a1\u30a4\u30eb\u3092\u4f5c\u6210\u3057\u3001\u30c0\u30d6\u30eb\u30af\u30ea\u30c3\u30af\u3057\u3066\u30d6\u30e9\u30a6\u30b6\u306b\u8868\u793a\u3057\u307e\u3059\u3002\u524d\u56de\u4f5c\u6210\u3057\u305fapp.js\u3001app.css\u3092\u5229\u7528\u3057\u3066\u3044\u307e\u3059\u3002<br \/>\n\u300c\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u300d\u3067\u3001\u4f5c\u6210\u3057\u305f\u30c7\u30fc\u30bf\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3057\u307e\u3059\u3002<br \/>\n\u753b\u9762\u4e0a\u90e8\u306e\u30b9\u30e9\u30a4\u30c0\u30fc\u307e\u305f\u306f\u300c\u2190\u300d\u300c\u2192\u300d\u30ad\u30fc\u3067\u623b\u308b\u30fb\u9032\u3080\u304c\u3067\u304d\u307e\u3059\u3002<br \/>\n\u30fbcheck.htm<\/p>\n<pre><code>&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=\"..\/data\/app.css\" &gt;\n    &lt;link rel=\"stylesheet\" type=\"text\/css\" href=\"https:\/\/code.jquery.com\/ui\/1.12.1\/themes\/base\/jquery-ui.css\" &gt;\n    &lt;style&gt;\n        a#download{\n            position: relative;\n            display: inline-block;\n            font-weight: bold;\n            padding: 0.25em 0.5em;\n            text-decoration: none;\n            color: #00BCD4;\n            background: #ECECEC;\n            transition: .4s;\n        }\n        a#download:hover{\n            background: #00bcd4;\n            color: white;\n        }       \n        #slider {\n            width: 640px;\n            margin: 10px 0;\n        } \n        #pos {\n            display: inline-block;\n        }\n        #labeling {\n            height: 60px;\n        }\n        #dt, #yw {\n            margin: 0 10px;\n        }\n        #yw {\n            display: inline-block;\n        }\n    &lt;\/style&gt;\n  &lt;\/head&gt;\n  &lt;body id=\"body\" onload=\"onBodyLoad()\"&gt;\n    &lt;div id=\"container\"&gt;\n      &lt;div id=\"labeling\"&gt;\n        &lt;form method=\"post\" enctype=\"multipart\/form-data\"&gt;\n            &lt;input type=\"file\" id=\"file\" accept=\"application\/json\"&gt;\n            &lt;!-- &lt;span&gt;&lt;a id=\"download\" href=\"#\" download=\"test.txt\" onclick=\"tmps.handleDownload()\"&gt;\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9&lt;\/a&gt;&lt;\/span&gt; --&gt;\n            &lt;div id=\"pos\"&gt;\n                &lt;span id=\"slider-pos\"&gt;&lt;\/span&gt;\n                &lt;span id=\"dt\"&gt;&lt;\/span&gt;\n                &lt;span id=\"yw\" style=\"display: none;\"&gt;\n                    &lt;select id=\"y\"&gt;\n                        &lt;option value=\"0\"&gt;\u30b0\u30fc&lt;\/option&gt;\n                        &lt;option value=\"1\"&gt;\u30c1\u30e7\u30ad&lt;\/option&gt;\n                        &lt;option value=\"2\"&gt;\u30d1\u30fc&lt;\/option&gt;\n                        &lt;!-- &lt;option value=\"3\"&gt;\uff13&lt;\/option&gt;\n                        &lt;option value=\"4\"&gt;\uff14&lt;\/option&gt;\n                        &lt;option value=\"5\"&gt;\uff15&lt;\/option&gt;\n                        &lt;option value=\"6\"&gt;\uff16&lt;\/option&gt;\n                        &lt;option value=\"7\"&gt;\uff17&lt;\/option&gt;\n                        &lt;option value=\"8\"&gt;\uff18&lt;\/option&gt;\n                        &lt;option value=\"9\"&gt;\uff19&lt;\/option&gt; --&gt;\n                    &lt;\/select&gt;\n                &lt;\/span&gt;\n            &lt;\/div&gt;\n        &lt;\/form&gt;\n        &lt;div id='slider'&gt;&lt;\/div&gt; \n      &lt;\/div&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;&amp;#x25c0;&lt;\/span&gt;&lt;span id=\"min-tmp\"&gt;&lt;\/span&gt;&lt;span id=\"min-up\" class=\"divisionBtn\"&gt;&amp;#x25b6;&lt;\/span&gt;&lt;\/div&gt;\n        &lt;div id=\"max-tmp-division\"&gt;&lt;span id=\"max-down\" class=\"divisionBtn\"&gt;&amp;#x25c0;&lt;\/span&gt;&lt;span id=\"max-tmp\"&gt;&lt;\/span&gt;&lt;span id=\"max-up\" class=\"divisionBtn\"&gt;&amp;#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=\"https:\/\/code.jquery.com\/jquery-3.3.1.min.js\"&gt;&lt;\/script&gt;\n    &lt;script src=\"https:\/\/code.jquery.com\/ui\/1.12.1\/jquery-ui.min.js\"&gt;&lt;\/script&gt;\n    &lt;script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/moment.js\/2.23.0\/moment.min.js\"&gt;&lt;\/script&gt;\n    &lt;script src=\"..\/data\/app.js\"&gt;&lt;\/script&gt;\n    &lt;script&gt;\n        const tmps = {\n            obj:null,\n            index: 0,\n            orgFileName: null,\n            handleDownload: function () {\n                var content = JSON.stringify(this.obj);\n                var blob = new Blob([ content ], { \"type\" : \"text\/plain\" });\n                var d = ge(\"download\");\n                d.download = this.orgFileName;\n                d.href = window.URL.createObjectURL(blob);\n            },\n            draw: function() {\n                const data = this.obj[this.index];\n                const timestamp = data[0];\n                const y = data[1];\n                const temperature = data[2];\n                this.setDt(timestamp);\n                cv.draw(temperature);\n                $(\"#y\").val(y);\n            },\n            setDt: function(timestamp) {\n                ge(\"dt\").innerHTML = moment.unix(timestamp).format();\n            }, \n            setY: function (value) {\n                value = parseInt(value);\n                if (value != this.obj[this.index][1]) {\n                    console.log(`y is ${value}`);\n                    this.obj[this.index][1] = value;\n                }           \n            }   \n        };\n        const slider = {\n            slider: null,\n            setUp: (length)=&gt; {\n                this.slider = $(\"#slider\").slider({\n                    value:0,\n                    min:0,\n                    max:length - 1,\n                    step:1,\n                    change: function (e, ui) {\n                        tmps.index = ui.value;\n                        tmps.draw();\n                    }\n                });\n            },\n            setValue: (value) =&gt; {\n                this.slider.slider(\"value\", value);\n            }\n        };\n        onBodyLoad = function(){\n            const reader = new FileReader();\n            \/\/HTML\u3092\u521d\u671f\u5316\u3057\u3001\u65b0\u305f\u306a\u30d5\u30a1\u30a4\u30eb\u3092\u6587\u5b57\u5217\u3068\u3057\u3066\u8aad\u8fbc\u3080     \n            file.addEventListener('change', function(e) {\n                tmps.orgFileName = e.target.files[0].name;\n                reader.readAsText(e.target.files[0]);\n            });\n            \/\/\u30d5\u30a1\u30a4\u30eb\u3092\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u5316\u3057\u3066\u8868\u793a\n            reader.onload = function(e) {\n                try {\n                    tmps.obj = JSON.parse(e.target.result);\n                } catch (err1) {\n                    console.log(err1);\n                    try {\n                        tmps.obj = JSON.parse('[' + e.target.result.slice( 0, -2 ) + ']');\n                    } catch (err2) {\n                        alert(\"json\u306b\u8aa4\u308a\u304c\u3042\u308a\u307e\u3059\u3002\");\n                        console.log(e2);\n                        return;\n                    }\n                }\n                console.log(tmps.obj);\n                slider.setUp(tmps.obj.length);\n                $(\"#yw\").show();\n                tmps.draw();\n            };\n\n            cv.createScale();\n            cv.createCanvas();\n        }\n        $(function() {\n            $(\"#y\").change(function() {\n                const value = $(this).val();\n                tmps.setY(value);\n            });\n            $(document).on('keydown', function(e) {\n                if (!tmps.obj) return;\n                console.log(`pressed keyCode:${e.keyCode}`);\n                if (48 &lt;= e.keyCode &amp;&amp; e.keyCode &lt;= 57) {\n                    const value = e.keyCode - 48;\n                    $(\"#y\").val(value);\n                    tmps.setY(value);\n                }\n                switch( e.keyCode ) {\n                    case 37:\n                        if (tmps.index &gt; 0) {\n                            console.log(\"\u623b\u308b\");\n                            tmps.index--;\n                            tmps.draw();\n                            slider.setValue(tmps.index);\n                        }\n                        break;\n                    case 39:\n                        \/\/ \u9032\u3080\n                        if (tmps.index &lt; tmps.obj.length) {\n                            console.log(\"\u9032\u3080\");\n                            tmps.index++;\n                            tmps.draw();\n                            slider.setValue(tmps.index);\n                        }                        \n                        break;\n                }\n            });\n        });                \n    &lt;\/script&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<p>\u78ba\u8a8d\u753b\u9762<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/check-400x340.png\" alt=\"\" width=\"600\" class=\"aligncenter size-medium wp-image-5527\" srcset=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/check-400x340.png 400w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/check-602x512.png 602w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/check.png 713w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/p>\n<h5>\u30c7\u30fc\u30bf\u3092\u6c34\u5897\u3057\u3059\u308b\uff08Data Augmentation\uff09<\/h5>\n<p>Keras\u306eImageDataGenerator\u3092\u4f7f\u3063\u3066\u3001\u30c7\u30fc\u30bf\u306e\u6c34\u5897\u3057\u3092\u884c\u3044\u307e\u3059\u3002\u753b\u50cf\u3092\u56de\u8ee2\u3084\u6c34\u5e73\uff0f\u5782\u76f4\u65b9\u5411\u306b\u79fb\u52d5\u30fb\u30ba\u30fc\u30e0\u7b49\u3057\u3066\u30c7\u30fc\u30bf\u309210\u500d\u306b\u3057\u307e\u3059\u3002<br \/>\n\u3053\u306e\u3068\u304d\u3001\u3064\u3044\u3067\u306b\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u30c7\u30fc\u30bf\u3092\u52a0\u5de5\u3057\u3066\u3044\u307e\u3059\u3002\u300c28\u5ea6\u4ee5\u4e0b\u306f0\u300d\u3068\u3044\u3046\u306e\u306f\u3001\u74b0\u5883\u306b\u3088\u3063\u3066\u306f\u3046\u307e\u304f\u3044\u304b\u306a\u3044\u304b\u3082\u3057\u308c\u306a\u3044\u3067\u3059\u3002<\/p>\n<ul>\n<li>28\u5ea6\u4ee5\u4e0b\u306f0<\/li>\n<li>35\u5ea6\u4ee5\u4e0a\u306f1<\/li>\n<li>0\u4ee5\u4e0a1\u4ee5\u4e0b\u306e\u5024\u306b\u5909\u63db<\/li>\n<\/ul>\n<p>\u3053\u308c\u3082\u5f8c\u3067\u78ba\u8a8d\u3059\u308b\u305f\u3081json\u30d5\u30a1\u30a4\u30eb\u3067\u51fa\u529b\u3057\u3068\u304d\u307e\u3059\u3002<br \/>\n\u30fbimage_data_generator.py<\/p>\n<pre><code class=\"python\">import json\nimport numpy as np\nimport scipy.stats\nfrom sklearn.model_selection import train_test_split\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom datetime import datetime\n\ndata_file = '&lt;\u5165\u529b\u30d5\u30a1\u30a4\u30eb\u3092\u8a2d\u5b9a\u3059\u308b&gt;'\nwith open(data_file) as f:\n    df = json.load(f)\nX = [data[2] for data in df]\nX = np.array(X)\n\n# 28\u5ea6\u4ee5\u4e0b\u30920\u300135\u5ea6\u4ee5\u4e0a\u30921\u3068\u3057\u30010\u4ee5\u4e0a1\u4ee5\u4e0b\u306e\u5024\u306b\u5909\u63db\nmax = 35\nmin = 28\nX = np.where(X &gt;max, 1, (X - min)\/(max - min))\nX = np.where(X &lt; 0, 0, X)\n\ny = [data[1] for data in df]\ny = np.array(y)\ny = y.reshape(y.shape[0], 1)\n\ndatagen = ImageDataGenerator(\n    rotation_range=90,  # \u6574\u6570\uff0e\u753b\u50cf\u3092\u30e9\u30f3\u30c0\u30e0\u306b\u56de\u8ee2\u3059\u308b\u56de\u8ee2\u7bc4\u56f2\n    width_shift_range=0.1,  # \u6d6e\u52d5\u5c0f\u6570\u70b9\u6570\uff08\u6a2a\u5e45\u306b\u5bfe\u3059\u308b\u5272\u5408\uff09\uff0e\u30e9\u30f3\u30c0\u30e0\u306b\u6c34\u5e73\u30b7\u30d5\u30c8\u3059\u308b\u7bc4\u56f2\n    height_shift_range=0.1,  # \u6d6e\u52d5\u5c0f\u6570\u70b9\u6570\uff08\u7e26\u5e45\u306b\u5bfe\u3059\u308b\u5272\u5408\uff09\uff0e\u30e9\u30f3\u30c0\u30e0\u306b\u5782\u76f4\u30b7\u30d5\u30c8\u3059\u308b\u7bc4\u56f2\n    fill_mode='constant',   # \u5165\u529b\u753b\u50cf\u306e\u5883\u754c\u5468\u308a\u3092\u57cb\u3081\u308b\u30e2\u30fc\u30c9\n    cval=0.0,               # constant\u30670.0\u3067\u57cb\u3081\u308b\n    horizontal_flip=True,  # \u771f\u7406\u5024\uff0e\u6c34\u5e73\u65b9\u5411\u306b\u5165\u529b\u3092\u30e9\u30f3\u30c0\u30e0\u306b\u53cd\u8ee2\u3057\u307e\u3059\n    vertical_flip=True,     # \u771f\u7406\u5024\uff0e\u5782\u76f4\u65b9\u5411\u306b\u5165\u529b\u3092\u30e9\u30f3\u30c0\u30e0\u306b\u53cd\u8ee2\u3057\u307e\u3059\n    zoom_range=0.3          # \u6d6e\u52d5\u5c0f\u6570\u70b9\u6570\u307e\u305f\u306f[lower\uff0cupper]\uff0e\u30e9\u30f3\u30c0\u30e0\u306b\u30ba\u30fc\u30e0\u3059\u308b\u7bc4\u56f2\uff0e\u6d6e\u52d5\u5c0f\u6570\u70b9\u6570\n    )  # randomly flip images\n\n# ImageDataGenerator\u306e\u5165\u529b\u5024\u306f(samples, channels, height, width)\u306a\u306e\u3067\u305d\u308c\u306b\u5408\u308f\u305b\u308b\nX = X.reshape(X.shape[0], 24, 32, 1)\n\n# \u7a7a\u306enumpy\u3092\u4f5c\u6210\u3057\u3001\u30eb\u30fc\u30d7\u3067append\u3059\u308b\nnew_X = np.empty((0, 24, 32, 1), float)\nnew_Y = np.empty((0, 1), int)\ncounter = 0\nfor x_batch, y_batch in datagen.flow(X, y, batch_size=32):\n    new_X = np.append(new_X, x_batch, axis=0)\n    new_Y = np.append(new_Y, y_batch, axis=0)\n    counter += 1\n    if counter &gt;= (X.shape[0] * 10 \/ 32):  # 10\u500d\u306b\u6c34\u5897\u3057\n        break\n\n# X\u306e\u5024\u30920=&lt;X&lt;=1 \u304b\u308928&lt;=X&lt;=35\u306b\u623b\u3059\nnew_X = new_X*(max - min) + min\nnew_X = new_X.reshape(new_X.shape[0], 32*24)\n\ndata = []\nfor (each_x, each_y) in zip(new_X, new_Y):\n    data.append([\n        datetime.now().timestamp(),\n        each_y[0],\n        each_x\n    ])\n\nclass MyEncoder(json.JSONEncoder):\n    def default(self, obj):\n        if isinstance(obj, np.integer):\n            return int(obj)\n        elif isinstance(obj, np.floating):\n            return float(obj)\n        elif isinstance(obj, np.ndarray):\n            return obj.tolist()\n        else:\n            return super(MyEncoder, self).default(obj)\n\npath = \"image_data_generator_%s.json\" % datetime.now().strftime(\"%Y%m%d%H%M%S\")\nwith open(path, mode='w') as f:\n    f.write(json.dumps(data, cls = MyEncoder))\n<\/code><\/pre>\n<p>ImageDataGenerator\u3067\u751f\u6210\u3057\u305f\u753b\u50cf\u306e\u4f8b<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/image_generator-400x100.png\" alt=\"\" width=\"600\" class=\"aligncenter size-medium wp-image-5528\" srcset=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/image_generator-400x100.png 400w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/image_generator-768x192.png 768w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/image_generator-602x150.png 602w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/image_generator.png 1983w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/p>\n<h5>\u30c7\u30fc\u30bf\u5909\u63db\u3057CSV\u30d5\u30a1\u30a4\u30eb\u4f5c\u6210<\/h5>\n<p>\u4e0a\u8a18\u3067\u4f5c\u6210\u3057\u305fJSON\u30d5\u30a1\u30a4\u30eb\u304b\u3089NNC\u306b\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3059\u308bCSV\u30d5\u30a1\u30a4\u30eb\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<br \/>\n\u30fbmake_csv.py<\/p>\n<pre><code class=\"python\">import json\nimport numpy as np\nimport scipy.stats\nfrom sklearn.model_selection import train_test_split\n\n\ndata_file = '&lt;\u5165\u529b\u30d5\u30a1\u30a4\u30eb\u3092\u8a2d\u5b9a\u3059\u308b&gt;'\nwith open(data_file) as f:\n    df = json.load(f)\nX = [data[2] for data in df]\nX = np.array(X)\n\n# 28\u5ea6\u4ee5\u4e0b\u30920\u300135\u5ea6\u4ee5\u4e0a\u30921\u3068\u3057\u30010\u4ee5\u4e0a1\u4ee5\u4e0b\u306e\u5024\u306b\u5909\u63db\nmax = 35\nmin = 28\nX = np.where(X &gt;max, 1, (X - min)\/(max - min))\nX = np.where(X &lt; 0, 0, X)\n\ny = [data[1] for data in df]\ny = np.array(y)\ny = y.reshape(y.shape[0], 1)\n\nindex = ['x__{0}'.format(i) for i in range(0, 768)]\nindex.append('y')\nheader = ','.join(index)\n\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)\ntrain_data = np.hstack((X_train, y_train))\ntest_data = np.hstack((X_test, y_test))\n\nnp.savetxt('&lt;train\u306e\u51fa\u529b\u30d5\u30a1\u30a4\u30eb\u3092\u8a2d\u5b9a\u3059\u308b&gt;', train_data, fmt='%.3f', delimiter=',', header=header, comments='')\nnp.savetxt('&lt;test\u306e\u51fa\u529b\u30d5\u30a1\u30a4\u30eb\u3092\u8a2d\u5b9a\u3059\u308b&gt;', test_data, fmt='%.3f', delimiter=',', header=header, comments='')\n<\/code><\/pre>\n<h5>NNC(\u30af\u30e9\u30a6\u30c9)\u3067\u5b66\u7fd2<\/h5>\n<p><a href=\"https:\/\/support.dl.sony.com\/docs-ja\/\u30c7\u30fc\u30bf\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u30c4\u30fc\u30eb\u306e\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\/\">NNC\u5c02\u7528\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c0\u30fc<\/a>\u3067train\u3068test\u30c7\u30fc\u30bf\u306eCSV\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002<\/p>\n<p>\u30b5\u30f3\u30d7\u30eb\u306b\u3042\u3063\u305fimage_recognition.MNIST.LeNet\u306e\u30e2\u30c7\u30eb\u3092\u307b\u307c\u305d\u306e\u307e\u307e\u4f7f\u3044\u307e\u3057\u305f\u3002<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/nnc_model-213x400.png\" alt=\"\" width=\"213\" height=\"400\" class=\"aligncenter size-medium wp-image-5529\" srcset=\"https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/nnc_model-213x400.png 213w, https:\/\/www.lancard.com\/blog\/wp-content\/uploads\/2019\/02\/nnc_model.png 293w\" sizes=\"auto, (max-width: 213px) 100vw, 213px\" \/><\/p>\n<p>\u30a4\u30f3\u30d7\u30c3\u30c8\u306f768\u500b(32&#215;24)\u306e\uff11\u6b21\u5143\u3001\u51fa\u529b\u306f\uff13\u3064\u3067\u3059\u3002<\/p>\n<p>\u306f\u307e\u3063\u305f\u306e\u304c\u3001ESP32\u306e\u30e1\u30e2\u30ea\u306e\u30b5\u30a4\u30ba\u3067\u3059\u3002<br \/>\n\u6700\u521d\u306b\u30b5\u30f3\u30d7\u30eb\u306b\u3042\u3063\u305f\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u307e\u307e\u3067\u4f5c\u6210\u3057\u305f\u3089\u3001\u751f\u6210\u3055\u308c\u305fESP32\u306b\u5b9f\u88c5\u3059\u308b\u91cd\u307f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u66f8\u304b\u308c\u305f\u30d5\u30a1\u30a4\u30eb(MainRuntime_parameters.c)\u304c2MB\u8fd1\u304f\u3042\u308a\u307e\u3057\u305f\u3002\u305d\u306e\u305f\u3081ESP32\u306e\u30b3\u30f3\u30d1\u30a4\u30eb\u306e\u30ea\u30f3\u30af\u6642\u306b\u4ee5\u4e0b\u306e\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002<\/p>\n<pre><code class=\"bash\">region `dram0_0_seg' overflowed by 225088 bytes\n<\/code><\/pre>\n<p>Convolution(\u7573\u307f\u8fbc\u307f)\u306e\u30d5\u30a3\u30eb\u30bf\u30fc\u6570\u3084\u30d5\u30a3\u30eb\u30bf\u30fc\u30b5\u30a4\u30ba\u3092\u8abf\u6574\u3057\u3066\u3001\u6700\u7d42\u7684\u306bMainRuntime_parameters.c\u306e\u30b5\u30a4\u30ba\u309230KB\u306b\u3057\u305f\u3089\u3001\u4e0a\u8a18\u30a8\u30e9\u30fc\u304c\u3067\u306a\u304f\u306a\u308a\u307e\u3057\u305f\u3002<\/p>\n<p>\u5b66\u7fd2\u3057\u305f\u7d50\u679c\u306e\u7cbe\u5ea6\uff08Acuacy\uff09\u3067\u3059\u304c\u3001\u6c34\u5897\u3057\uff08Data Augmentation)\u3057\u306a\u304b\u3063\u305f\u5834\u5408\u306f\u30010.9865\u3067\u3059\u304c\u3001\u6c34\u5897\u3057\u3057\u305f\u5834\u5408\u30010.8768\u3068\u306a\u308a\u307e\u3057\u305f\u3002\u30c7\u30fc\u30bf\u3092\u52a0\u5de5\u3057\u3059\u304e\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002<\/p>\n<h5>\u5b66\u7fd2\u6e08\u307f\u30e2\u30c7\u30eb\u3092ESP32\u306b\u5b9f\u88c5<\/h5>\n<p>\u25a0NNP\u3092\u4f7f\u3063\u305f\u5b9f\u88c5\u306e\u5834\u5408<br \/>\nNNP\u30d5\u30a1\u30a4\u30eb\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002<br \/>\n\u4ee5\u4e0b\u306e\u30b3\u30de\u30f3\u30c9\u3067\u5c55\u958b\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"bash\">$ nnabla_cli convert -O CSRC -b 1 result_evaluate.nnp &lt;\u51fa\u529b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea&gt;\n<\/code><\/pre>\n<p>\u4ee5\u4e0b\u306e\uff15\u3064\u306e\u30d5\u30a1\u30a4\u30eb\u304c\u3067\u304d\u307e\u3059\u3002<br \/>\n\u30fbGNUmakefile<br \/>\n\u30fbMainRuntime_example.c        \/\/ \u30b5\u30f3\u30d7\u30eb\u30d7\u30ed\u30b0\u30e9\u30e0<br \/>\n\u30fbMainRuntime_inference.c\u3000    \/\/ \u63a8\u8ad6\u3059\u308b\u30d7\u30ed\u30b0\u30e9\u30e0<br \/>\n\u30fbMainRuntime_inference.h<br \/>\n\u30fbMainRuntime_parameters.c\u3000\u3000\/\/ \u91cd\u307f\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u914d\u5217<br \/>\n\u30fbMainRuntime_parameters.h<\/p>\n<p>MainRuntime_inference.c\u3001MainRuntime_inference.h\u3001MainRuntime_parameters.c\u3001ainRuntime_parameters.h\u3092lib\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u4ee5\u4e0b\u306b\u914d\u7f6e\u3057\u307e\u3059\u3002<\/p>\n<p>\u3053\u308c\u3089\u306fnnabla-c-runtime\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u4f9d\u5b58\u3057\u307e\u3059\u306e\u3067\u3001platformio.ini\u306b\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u8ffd\u8a18\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"bash\">lib_deps = https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer.git, https:\/\/github.com\/sony\/nnabla-c-runtime.git\n<\/code><\/pre>\n<p>\u63a8\u8ad6\u3092\u5b9f\u88c5\u3057\u305f\u30d7\u30ed\u30b0\u30e9\u30e0\uff08NNP\u7248\uff09\u3067\u3059\u3002<br \/>\n\u30fbmain.c<\/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#include \"MainRuntime_inference.h\"\n#include \"MainRuntime_parameters.h\"\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 *_context = NULL;\n\nint mode = 0;\n\n\/\/ template &lt;class T, size_t N&gt;\n\/\/ void standard(T (&amp;data)[N])\n\/\/ {\n\/\/   float ave = std::accumulate(std::begin(data), std::end(data), 0.0) \/ N;\n\/\/   float sd = sqrt(std::inner_product(std::begin(data), std::end(data), std::begin(data), 0.0) \/ N - ave * ave);\n\/\/   std::for_each(std::begin(data), std::end(data), [&amp;ave, &amp;sd](float &amp;temperature) {\n\/\/     temperature = (temperature - ave) \/ sd;\n\/\/   });\n\/\/ }\n\n\/\/ 28\u5ea6\u4ee5\u4e0b\u30920\u300135\u5ea6\u4ee5\u4e0a\u30921\u3068\u3057\u30010\u4ee5\u4e0a1\u4ee5\u4e0b\u306e\u5024\u306b\u5909\u63db\ntemplate &lt;class T, size_t N&gt;\nint normalize(T (&amp;data)[N], float min, float max)\n{\n  int cnt = 0;\n  std::for_each(std::begin(data), std::end(data), [&amp;min, &amp;max, &amp;cnt](float &amp;temperature) {\n    if (min &gt; temperature)\n    {\n      temperature = 0;\n      cnt++;\n    } else if (max &lt; temperature) {\n      temperature = 1;\n    } else {\n      temperature = (temperature - min)\/(max - min);\n    }\n  });\n  return cnt;\n}\n\nint predict(float *data, float r)\n{\n  memcpy(nnablart_mainruntime_input_buffer(_context, 0), data, 768*4);\n  nnablart_mainruntime_inference(_context);\n  float *probs = nnablart_mainruntime_output_buffer(_context, 0);\n\n  Serial.printf(\"predict %.3f, %.3f, %.3f\\n\", probs[0], probs[1], probs[2]);\n  for (int cl = 0; cl &lt; NNABLART_MAINRUNTIME_OUTPUT0_SIZE; cl++)\n  {\n    if (probs[cl] &gt; r)\n    {\n      return cl;\n    }\n  }\n  return 9;\n}\n\nvoid onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)\n{\n  if (type == WS_EVT_CONNECT)\n  {\n    Serial.printf(\"ws[%s][%u] connect\\n\", server-&gt;url(), client-&gt;id());\n  }\n  else if (type == WS_EVT_DISCONNECT)\n  {\n    Serial.printf(\"ws[%s][%u] disconnect\\n\", server-&gt;url(), client-&gt;id());\n  }\n  else if (type == WS_EVT_ERROR)\n  {\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{\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\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{\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{\n  Wire.begin();\n  Serial.begin(115200);\n  Serial.setDebugOutput(true);\n  WiFi.begin(ssid, password);\n\n  while (WiFi.status() != WL_CONNECTED)\n  {\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  {\n    Serial.println(\"Error setting up MDNS responder!\");\n    while (1)\n    {\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  \/\/ predict\u30e2\u30fc\u30c9\u958b\u59cb\n  server.on(\"\/start\", HTTP_GET, [](AsyncWebServerRequest *request) {\n    _context = nnablart_mainruntime_allocate_context(MainRuntime_parameters);\n    mode = 1;\n    request-&gt;send(200, \"text\/plain\", String(\"ok\"));\n  });\n\n  \/\/ predict\u30e2\u30fc\u30c9\u7d42\u4e86\n  server.on(\"\/stop\", HTTP_GET, [](AsyncWebServerRequest *request) {\n    mode = 0;\n    nnablart_mainruntime_free_context(_context);\n    request-&gt;send(200, \"text\/plain\", String(\"ok\"));\n  });\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{\n  ArduinoOTA.handle();\n\n  \/\/ WebSocket\u63a5\u7d9a\u3057\u3066\u306a\u3044\u6642\u306f\u4f55\u3082\u3057\u306a\u3044\n  if (ws.count() &lt;= 0)\n  {\n    return;\n  }\n\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  int top_class = 9;\n  if (mode == 1)\n  {\n    \/\/ 28\u5ea6\u4ee5\u4e0b\u30920\u300135\u5ea6\u4ee5\u4e0a\u30921\u3068\u3057\u30010\u4ee5\u4e0a1\u4ee5\u4e0b\u306e\u5024\u306b\u5909\u63db\n    int cnt = normalize(mlx90640To, 28, 35);\n\n    Serial.printf(\"predict mode: count of below 28C: %d\\n\", cnt);\n\n    \/\/ 28\u5ea6\u4ee5\u4e0b\u304c768\u30c9\u30c3\u30c8\u4e2d\u306e700\u30c9\u30c3\u30c8\u4ee5\u4e0a\u306e\u5834\u5408\u306f\u3001predict\u3057\u306a\u3044\n    if (cnt &lt; 700)\n    {\n      \/\/ \u7cbe\u5ea6\u304c0.5\u4ee5\u4e0a\u306e\u5834\u5408\u306e\u307f\u3001\u7d50\u679c\u3092\u8fd4\u3059\n      top_class = predict(mlx90640To, 0.5);\n    }\n    ws.textAll(\"result:\" + String(top_class));\n  }\n  long finishedTime = millis();\n  Serial.printf(\"calculated secs:%.2f, finished secs:%.2f, top_class: %d\\n\", (float)(calculatedTime - startTime) \/ 1000, (float)(finishedTime - startTime) \/ 1000, top_class);\n}\n<\/code><\/pre>\n<p>\u25a0NNB\u3092\u4f7f\u3063\u305f\u5b9f\u88c5\u306e\u5834\u5408<br \/>\nNNB\u30d5\u30a1\u30a4\u30eb\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002<br \/>\nSPIFFS\u3067\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u3081\u308b\u3088\u3046\u306b\u3059\u308b\u305f\u3081\u3001data\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u4ee5\u4e0b\u306bNNB\u30d5\u30a1\u30a4\u30eb\u3092\u7f6e\u304d\u307e\u3059\u3002<\/p>\n<p>nnabla-c-runtime\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u4f9d\u5b58\u3057\u307e\u3059\u306e\u3067\u3001platformio.ini\u306b\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u8ffd\u8a18\u3057\u307e\u3059\u3002<\/p>\n<pre><code class=\"bash\">lib_deps = https:\/\/github.com\/me-no-dev\/ESPAsyncWebServer.git, https:\/\/github.com\/sony\/nnabla-c-runtime.git\n<\/code><\/pre>\n<p>\u63a8\u8ad6\u3092\u5b9f\u88c5\u3057\u305f\u30d7\u30ed\u30b0\u30e9\u30e0\uff08NNB\u7248\uff09\u3067\u3059\u3002<br \/>\nNNB\u30d5\u30a1\u30a4\u30eb\u3092char\u306e\u914d\u5217\u3068\u3057\u3066\u8aad\u307f\u8fbc\u3093\u3067\u3001\u305d\u308c\u3092nn_network_t\u69cb\u9020\u4f53\u306b\u30ad\u30e3\u30b9\u30c8\u3057\u3066\u3044\u307e\u3059\u3002<br \/>\nNNB\u30d5\u30a1\u30a4\u30eb\u306e\u30b5\u30a4\u30ba\u306f98KB\u3060\u3068\u5927\u4e08\u592b\u3067\u3057\u305f\u304c\u3001136KB\u3060\u3068\u8aad\u307f\u8fbc\u307f\u6642\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u4f7f\u3048\u308b\u30d2\u30fc\u30d7\u30b5\u30a4\u30ba\u306f150KB\u4ee5\u4e0a\u3042\u308b\u306e\u3067\u3059\u304c\u3002\u9023\u7d9a\u3057\u305f\u30d2\u30fc\u30d7\u30e1\u30e2\u30ea\u304c\u5fc5\u8981\u3060\u304b\u3089\u304b\u3082\u3057\u308c\u307e\u305b\u3093\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\/\/ #include \"MainRuntime_inference.h\"\n\/\/ #include \"MainRuntime_parameters.h\"\n#include &lt;nnablart\/network.h&gt;\n#include &lt;nnablart\/runtime.h&gt;\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 *_context = NULL;\n\nint mode = 0;\n\nchar *nnb;\n\n\n\/\/ template &lt;class T, size_t N&gt;\n\/\/ void standard(T (&amp;data)[N])\n\/\/ {\n\/\/   float ave = std::accumulate(std::begin(data), std::end(data), 0.0) \/ N;\n\/\/   float sd = sqrt(std::inner_product(std::begin(data), std::end(data), std::begin(data), 0.0) \/ N - ave * ave);\n\/\/   std::for_each(std::begin(data), std::end(data), [&amp;ave, &amp;sd](float &amp;temperature) {\n\/\/     temperature = (temperature - ave) \/ sd;\n\/\/   });\n\/\/ }\n\n\/\/ 28\u5ea6\u4ee5\u4e0b\u30920\u300135\u5ea6\u4ee5\u4e0a\u30921\u3068\u3057\u30010\u4ee5\u4e0a1\u4ee5\u4e0b\u306e\u5024\u306b\u5909\u63db\ntemplate &lt;class T, size_t N&gt;\nint normalize(T (&amp;data)[N], float min, float max)\n{\n  int cnt = 0;\n  std::for_each(std::begin(data), std::end(data), [&amp;min, &amp;max, &amp;cnt](float &amp;temperature) {\n    if (min &gt; temperature)\n    {\n      temperature = 0;\n      cnt++;\n    } else if (max &lt; temperature) {\n      temperature = 1;\n    } else {\n      temperature = (temperature - min)\/(max - min);\n    }\n  });\n  return cnt;\n}\n\nint predict(float *data, float r)\n{\n  memcpy(rt_input_buffer(_context, 0), data, 768*4);\n  rt_forward(_context);\n\n  \/\/ Serial.printf(\"num:%d, \", rt_num_of_output(_context));\n  \/\/ Serial.printf(\"size:%d\\n\", rt_output_size(_context, 0));\n\n  float  *probs = (float *)rt_output_buffer(_context, 0);\n\n  Serial.printf(\"predict %.3f, %.3f, %.3f\\n\", probs[0], probs[1], probs[2]);\n  for (int cl = 0; cl &lt; 3; cl++)\n  {\n    if (probs[cl] &gt; r)\n    {\n      return cl;\n    }\n  }\n  return 9;\n}\n\nvoid onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)\n{\n  if (type == WS_EVT_CONNECT)\n  {\n    Serial.printf(\"ws[%s][%u] connect\\n\", server-&gt;url(), client-&gt;id());\n  }\n  else if (type == WS_EVT_DISCONNECT)\n  {\n    Serial.printf(\"ws[%s][%u] disconnect\\n\", server-&gt;url(), client-&gt;id());\n  }\n  else if (type == WS_EVT_ERROR)\n  {\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{\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\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{\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{\n  Wire.begin();\n  Serial.begin(115200);\n  Serial.setDebugOutput(true);\n  WiFi.begin(ssid, password);\n\n  while (WiFi.status() != WL_CONNECTED)\n  {\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  {\n    Serial.println(\"Error setting up MDNS responder!\");\n    while (1)\n    {\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  \/\/ predict\u30e2\u30fc\u30c9\u958b\u59cb\n  server.on(\"\/start\", HTTP_GET, [](AsyncWebServerRequest *request) {\n    \/\/ _context = nnablart_mainruntime_allocate_context(MainRuntime_parameters);\n\n    \/* READ FILE *\/\n    File fp = SPIFFS.open(\"\/result.nnb\", FILE_READ); \/\/ \u8aad\u307f\u53d6\u308a\n    Serial.printf(\"file size:%d\\n\", fp.size());\n    rt_return_value_t ret = rt_allocate_context(&amp;_context);\n    nnb = (char *)malloc(fp.size());  \/\/ malloc\u4f7f\u308f\u306a\u3044\u3068\u30d0\u30c3\u30d5\u30a1\u30fc\u30aa\u30fc\u30d0\u30fc\u30d5\u30ed\u30fc\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u305f\n    fp.readBytes(nnb, fp.size());\n    fp.close();\n\n    nn_network_t *net = (nn_network_t *)nnb;\n    ret = rt_initialize_context(_context, net);\n    Serial.println(ret);\n\n    mode = 1;\n    request-&gt;send(200, \"text\/plain\", String(\"ok\"));\n  });\n\n  \/\/ predict\u30e2\u30fc\u30c9\u7d42\u4e86\n  server.on(\"\/stop\", HTTP_GET, [](AsyncWebServerRequest *request) {\n    mode = 0;\n\n    rt_free_context(&amp;_context);\n    free(nnb);\n\n    request-&gt;send(200, \"text\/plain\", String(\"ok\"));\n  });\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{\n  ArduinoOTA.handle();\n\n  \/\/ WebSocket\u63a5\u7d9a\u3057\u3066\u306a\u3044\u6642\u306f\u4f55\u3082\u3057\u306a\u3044\n  if (ws.count() &lt;= 0)\n  {\n    return;\n  }\n\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  int top_class = 9;\n  if (mode == 1)\n  {\n    \/\/ 28\u5ea6\u4ee5\u4e0b\u30920\u300135\u5ea6\u4ee5\u4e0a\u30921\u3068\u3057\u30010\u4ee5\u4e0a1\u4ee5\u4e0b\u306e\u5024\u306b\u5909\u63db\n    int cnt = normalize(mlx90640To, 28, 35);\n\n    Serial.printf(\"predict mode: count of below 28C: %d\\n\", cnt);\n\n    \/\/ 28\u5ea6\u4ee5\u4e0b\u304c768\u30c9\u30c3\u30c8\u4e2d\u306e700\u30c9\u30c3\u30c8\u4ee5\u4e0a\u306e\u5834\u5408\u306f\u3001predict\u3057\u306a\u3044\n    if (cnt &lt; 700)\n    {\n      \/\/ \u7cbe\u5ea6\u304c0.5\u4ee5\u4e0a\u306e\u5834\u5408\u306e\u307f\u3001\u7d50\u679c\u3092\u8fd4\u3059\n      top_class = predict(mlx90640To, 0.5);\n    }\n    ws.textAll(\"result:\" + String(top_class));\n  }\n  long finishedTime = millis();\n  Serial.printf(\"calculated secs:%.2f, finished secs:%.2f, top_class: %d\\n\", (float)(calculatedTime - startTime) \/ 1000, (float)(finishedTime - startTime) \/ 1000, top_class);\n}\n<\/code><\/pre>\n<p>\u63a8\u8ad6\u306e\u7d50\u679c\u3092\u30d6\u30e9\u30a6\u30b6\u3067\u8868\u793a\u3059\u308b\u305f\u3081HTML,js\u3001css\u3092\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u4fee\u6b63\u3057\u307e\u3057\u305f\u3002<br \/>\n\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;div id=\"header\"&gt;&lt;span&gt;&lt;a id=\"predict\" href=\"#\"&gt;\u5224\u5b9a\u3059\u308b&lt;\/a&gt;&lt;\/span&gt;\n      &lt;\/div&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;&amp;#x25c0;&lt;\/span&gt;&lt;span id=\"min-tmp\"&gt;&lt;\/span&gt;&lt;span id=\"min-up\" class=\"divisionBtn\"&gt;&amp;#x25b6;&lt;\/span&gt;&lt;\/div&gt;\n        &lt;div id=\"max-tmp-division\"&gt;&lt;span id=\"max-down\" class=\"divisionBtn\"&gt;&amp;#x25c0;&lt;\/span&gt;&lt;span id=\"max-tmp\"&gt;&lt;\/span&gt;&lt;span id=\"max-up\" class=\"divisionBtn\"&gt;&amp;#x25b6;&lt;\/span&gt;&lt;\/div&gt;\n      &lt;\/div&gt;\n      &lt;div id=\"messages\"&gt;&lt;\/div&gt;\n      &lt;div id=\"result\"&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.js<\/p>\n<pre><code class=\"js\">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        console.log(predict.mode);\n        const result = ge(\"result\");\n        const resultStrings = { \"0\": \"\u30b0\u30fc\", \"1\": \"\u30c1\u30e7\u30ad\", \"2\": \"\u30d1\u30fc\" };\n        const m = e.data.match(\/^result:([0-2])\/);\n        if (m) {\n          result.innerHTML = resultStrings[m[1]];\n        } else {\n          result.innerHTML = \"\";\n        }\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 (true) {\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\nconst predict = {\n  mode: false,\n  sw: function () {\n    const elem = ge(\"predict\");\n    const result = ge(\"result\");\n    if (this.mode) {\n      fetch(\"stop\");\n      elem.classList.remove('predictiong');\n      elem.innerHTML = \"\u5224\u5b9a\u3059\u308b\";\n      result.style.display = \"none\";\n      this.mode = false;\n    } else {\n      fetch(\"start\");\n      elem.classList.add('predictiong');\n      elem.innerHTML = \"\u5224\u5b9a\u4e2d\";\n      result.style.display = \"block\";\n      this.mode = true;\n    }\n  }\n}\n\nlet onBodyLoad = function () {\n  cv.createScale();\n  skt.start();\n  cv.createCanvas();\n\n  ge(\"predict\").onclick = predict.sw;\n}\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#container {\n  position: relative;\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#result {\n  position: absolute;\n  right: 1px;\n  top: 1px;\n  height: 18px;\n  width: 50px;\n  background: #faf62d;\n  padding: 3px 10px;\n  color: #000000;\n  font-weight: bold;\n  display: none;\n  top: 30px;\n}\n#header {\n  text-align: right;\n  padding-bottom: 5px;\n}\na#predict{\n  position: relative;\n  display: inline-block;\n  font-weight: bold;\n  padding: 0.25em 0.5em;\n  text-decoration: none;\n  color: rgb(242, 248, 250);\n  background: rgb(20, 85, 7);\n  transition: .4s;\n  width: 80px;\n  text-align: center;\n}\na#predict.predictiong {\n  background: rgb(230, 33, 7);\n}\na#predict:hover{\n    background: #5bf15b;\n    color: white;\n}       \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<h5>\u7d50\u679c<\/h5>\n<p>\u4e0a\u8a18\u30d7\u30ed\u30b0\u30e9\u30e0\u3092\u5b9f\u884c\u3057\u305f\u7d50\u679c\u3001\u3060\u3044\u305f\u3044\u6b63\u78ba\u306b\u63a8\u8ad6\u3059\u308b\u3088\u3046\u3067\u3057\u305f\u3002<br \/>\n\u305f\u3060\u3057\u80cc\u666f\u306b\u71b1\u3092\u6301\u3064\u3082\u306e\u3001\u30e2\u30cb\u30bf\u3068\u304b\u86cd\u5149\u706f\u7b49\u304c\u3042\u308b\u3068\u3001\u30ce\u30a4\u30ba\u304c\u5165\u3063\u3066\u3046\u307e\u304f\u3044\u304b\u306a\u3044\u3067\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%2F5523&#038;t=ESP32%E3%81%A7%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0&#038;s=100&#038;p&#091;url&#093;=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5523&#038;p&#091;images&#093;&#091;0&#093;=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F01%2Fjyanken.gif&#038;p&#091;title&#093;=ESP32%E3%81%A7%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0\" 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%2F5523&#038;text=ESP32%E3%81%A7%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0\" 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%2F5523&#038;title=ESP32%E3%81%A7%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0\" 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=ESP32%E3%81%A7%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0&#038;u=https%3A%2F%2Fwww.lancard.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F5523\" 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=ESP32%E3%81%A7%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0&#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%2F5523\" 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>\u5148\u65e5\u4f5c\u3063\u305f\u71b1\u753b\u50cf\u3092\u30ea\u30a2\u30eb\u30bf\u30a4\u30e0\u3067\u898b\u308c\u308b\u30b7\u30b9\u30c6\u30e0\u3092\u6539\u9020\u3057\u3001\u30c7\u30a3\u30fc\u30d7\u30e9\u30fc\u30cb\u30f3\u30b0\u3057\u3066\u307f\u307e\u3057\u305f\u3002 \u30b8\u30e3\u30f3\u30b1\u30f3\u306e\uff13\u3064\u306e\u30b8\u30a7\u30b9\u30c1\u30e3\u30fc\u3092\u3001\u8d64\u5916\u7dda\u30a2\u30ec\u30a4\u30e2\u30b8\u30e5\u30fc\u30eb\u304b\u3089\u306e\u5165\u529b\u30c7\u30fc\u30bf\u3092\u3082\u3068\u306b\u63a8\u8ad6\u3057\u307e\u3059\u3002 \u30b8\u30e3\u30f3\u30b1\u30f3\u306e\u753b\u50cf\u30c7\u30fc\u30bf\u3092\u4f7f\u3044\u30c7\u30a3\u30fc\u30d7 [&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":[176,183],"class_list":["post-5523","post","type-post","status-publish","format-standard","hentry","category-iot","category-1","tag-esp32","tag-183"],"_links":{"self":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/5523","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=5523"}],"version-history":[{"count":5,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/5523\/revisions"}],"predecessor-version":[{"id":5534,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/posts\/5523\/revisions\/5534"}],"wp:attachment":[{"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/media?parent=5523"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/categories?post=5523"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lancard.com\/blog\/wp-json\/wp\/v2\/tags?post=5523"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}