{"id":93,"date":"2026-06-09T16:05:25","date_gmt":"2026-06-09T07:05:25","guid":{"rendered":"https:\/\/fideafact.ddns.net\/?p=93"},"modified":"2026-06-09T16:05:25","modified_gmt":"2026-06-09T07:05:25","slug":"dht22raspzw2%e3%81%ae%e6%b8%a9%e6%b9%bf%e5%ba%a6%e3%83%87%e3%83%bc%e3%82%bf%e3%82%92%e3%80%81%e9%81%a0%e3%81%8f%e9%9b%a2%e3%82%8c%e3%81%9ffideafact-ddns-net%e3%81%ab%e9%80%81%e3%81%a3%e3%81%a6wordpr-2","status":"publish","type":"post","link":"https:\/\/fideafact.ddns.net\/?p=93","title":{"rendered":"DHT22+RaspZW2\u306e\u6e29\u6e7f\u5ea6\u30c7\u30fc\u30bf\u3092\u3001\u9060\u304f\u96e2\u308c\u305fFideafact.ddns.net\u306b\u9001\u3063\u3066WordPress\u3067\u30b0\u30e9\u30d5\u3067\u898b\u308b\u65b9\u6cd5\u3000Part2"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u69cb\u6210\u3068\u3057\u3066\u306f\u30012\u53f0\uff081\u53f0\u3067\u3082\u8907\u6570\u53f0\u3067\u3082\uff09\u306e&nbsp;<strong>Raspberry Pi Zero W 2 + DHT22<\/strong>&nbsp;\u304b\u3089\u5b9a\u671f\u7684\u306b\u6e29\u6e7f\u5ea6\u3092\u6e2c\u5b9a\u3057\u3001\u5916\u90e8\u30b5\u30fc\u30d0\u30fc&nbsp;Fideafact.fideafact.fideafact.ddns.net\/sensor\/data&nbsp;\u306bHTTP\u3067\u9001\u4fe1\u3057\u3001WordPress\u5074\u3067DB\u4fdd\u5b58\u30fb\u30b0\u30e9\u30d5\u8868\u793a\u3059\u308b\u5f62\u3067\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u5168\u4f53\u69cb\u6210<\/strong><\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>DHT22 + Raspberry Pi 1\n        |\n        | HTTPS POST\n        v\nFideafact.fideafact.fideafact.ddns.net\/sensor\/data \/ WordPress \/ API\n        ^\n        | HTTPS POST\n        |\nDHT22 + Raspberry Pi 2\n\nWordPress\u30da\u30fc\u30b8\u3067\u30b0\u30e9\u30d5\u8868\u793a<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u304a\u3059\u3059\u3081\u65b9\u5f0f<\/strong><\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Raspberry Pi\u3067DHT22\u3092\u8aad\u3080<\/li>\n\n\n\n<li>WordPress\u306b\u5c02\u7528API\u3092\u4f5c\u308b<\/li>\n\n\n\n<li>\u6e29\u5ea6\u30fb\u6e7f\u5ea6\u30fb\u7aef\u672bID\u30fb\u6642\u523b\u3092WordPress\u306eDB\u3078\u4fdd\u5b58<\/li>\n\n\n\n<li>WordPress\u56fa\u5b9a\u30da\u30fc\u30b8\u306bChart.js\u3067\u30b0\u30e9\u30d5\u8868\u793a<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Raspberry Pi\u5074<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">DHT22\u914d\u7dda\u4f8b\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DHT22 VCC  -> 3.3V\nDHT22 GND  -> GND\nDHT22 DATA -> GPIO4<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Python\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u5165\u308c\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-a25f433e707ad3d3daa563a8157a35d9\"><code>sudo apt update\nsudo apt install python3-pip\npip3 install adafruit-circuitpython-dht requests\nsudo apt install libgpiod2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u9001\u4fe1\u7528\u30b9\u30af\u30ea\u30d7\u30c8\u4f8b\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-024b3643e0a7e805a41d1be4cb00d9d6\"><code>import time\nimport board\nimport adafruit_dht\nimport requests\n\nDEVICE_ID = \"raspi-1\"  # 2\u53f0\u76ee\u306f raspi-2 \u306a\u3069\u306b\u5909\u66f4\nAPI_URL = \"https:\/\/Fideafact.fideafact.fideafact.ddns.net\/sensor\/data\/wp-json\/dht22\/v1\/submit\"\nAPI_KEY = \"your-secret-key\"\n\ndht = adafruit_dht.DHT22(board.D4)\n\nwhile True:\n    try:\n        temperature = dht.temperature\n        humidity = dht.humidity\n\n        data = {\n            \"device_id\": DEVICE_ID,\n            \"temperature\": temperature,\n            \"humidity\": humidity,\n            \"api_key\": API_KEY\n        }\n\n        r = requests.post(API_URL, json=data, timeout=10)\n        print(r.status_code, r.text)\n\n    except Exception as e:\n        print(\"Error:\", e)\n\n    time.sleep(300)  # 5\u5206\u3054\u3068<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u81ea\u52d5\u8d77\u52d5\u306f&nbsp;cron&nbsp;\u3067\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-feeb2e5d0043e6ff1560314a25e8f1a6\"><code>crontab -e<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">crontab\u306b\u8ffd\u52a0\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-e84a31c5552c0004c68d281aeb0f7184\"><code>@reboot \/usr\/bin\/python3 \/home\/pi\/dht22_sender.py<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2. WordPress\u5074\u306b\u4fdd\u5b58API\u3092\u4f5c\u308b<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u4e00\u756a\u30b7\u30f3\u30d7\u30eb\u306a\u306e\u306f\u3001WordPress\u306b\u5c0f\u3055\u306a\u81ea\u4f5c\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u5165\u308c\u308b\u65b9\u6cd5\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">wp-content\/plugins\/dht22-logger\/dht22-logger.php<\/mark><\/strong>\u00a0\u3092\u4f5c\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-670763e09e7cb3d37c71ad7f11cd3e9b\"><code>&lt;?php\n\/*\nPlugin Name: DHT22 Logger\n*\/\n\nadd_action('rest_api_init', function () {\n    register_rest_route('dht22\/v1', '\/submit', &#91;\n        'methods' =&gt; 'POST',\n        'callback' =&gt; 'dht22_submit',\n        'permission_callback' =&gt; '__return_true'\n    ]);\n\n    register_rest_route('dht22\/v1', '\/data', &#91;\n        'methods' =&gt; 'GET',\n        'callback' =&gt; 'dht22_data',\n        'permission_callback' =&gt; '__return_true'\n    ]);\n});\n\nregister_activation_hook(__FILE__, function () {\n    global $wpdb;\n    $table = $wpdb-&gt;prefix . 'dht22_logs';\n    $charset = $wpdb-&gt;get_charset_collate();\n\n    $sql = \"CREATE TABLE $table (\n        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n        device_id VARCHAR(50) NOT NULL,\n        temperature FLOAT NOT NULL,\n        humidity FLOAT NOT NULL,\n        created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n        PRIMARY KEY (id),\n        INDEX device_time (device_id, created_at)\n    ) $charset;\";\n\n    require_once ABSPATH . 'wp-admin\/includes\/upgrade.php';\n    dbDelta($sql);\n});\n\nfunction dht22_submit($request) {\n    global $wpdb;\n\n    $params = $request-&gt;get_json_params();\n\n    if (($params&#91;'api_key'] ?? '') !== 'your-secret-key') {\n        return new WP_Error('forbidden', 'Invalid API key', &#91;'status' =&gt; 403]);\n    }\n\n    $wpdb-&gt;insert($wpdb-&gt;prefix . 'dht22_logs', &#91;\n        'device_id' =&gt; sanitize_text_field($params&#91;'device_id']),\n        'temperature' =&gt; floatval($params&#91;'temperature']),\n        'humidity' =&gt; floatval($params&#91;'humidity']),\n    ]);\n\n    return &#91;'ok' =&gt; true];\n}\n\nfunction dht22_data($request) {\n    global $wpdb;\n\n    $table = $wpdb-&gt;prefix . 'dht22_logs';\n\n    return $wpdb-&gt;get_results(\"\n        SELECT device_id, temperature, humidity, created_at\n        FROM $table\n        WHERE created_at &gt;= DATE_SUB(NOW(), INTERVAL 24 HOUR)\n        ORDER BY created_at ASC\n    \");\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress\u7ba1\u7406\u753b\u9762\u3067&nbsp;<strong>DHT22 Logger<\/strong>&nbsp;\u3092\u6709\u52b9\u5316\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. WordPress\u3067\u30b0\u30e9\u30d5\u8868\u793a<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u56fa\u5b9a\u30da\u30fc\u30b8\u306b\u4ee5\u4e0b\u306e\u3088\u3046\u306aHTML\u3092\u5165\u308c\u307e\u3059\u3002<br>Chart.js\u3092\u4f7f\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-04115b0ec2cc1b41db96042da7553532\"><code>&lt;canvas id=\"tempChart\"&gt;&lt;\/canvas&gt;\n&lt;canvas id=\"humChart\"&gt;&lt;\/canvas&gt;\n\n&lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"&gt;&lt;\/script&gt;\n&lt;script&gt;\nfetch('\/wp-json\/dht22\/v1\/data')\n  .then(res =&gt; res.json())\n  .then(rows =&gt; {\n    const labels = rows.map(r =&gt; r.created_at);\n\n    const devices = &#91;...new Set(rows.map(r =&gt; r.device_id))];\n\n    const tempDatasets = devices.map(device =&gt; ({\n      label: device + ' \u6e29\u5ea6',\n      data: rows.filter(r =&gt; r.device_id === device).map(r =&gt; r.temperature),\n      borderWidth: 2\n    }));\n\n    const humDatasets = devices.map(device =&gt; ({\n      label: device + ' \u6e7f\u5ea6',\n      data: rows.filter(r =&gt; r.device_id === device).map(r =&gt; r.humidity),\n      borderWidth: 2\n    }));\n\n    new Chart(document.getElementById('tempChart'), {\n      type: 'line',\n      data: {\n        labels,\n        datasets: tempDatasets\n      }\n    });\n\n    new Chart(document.getElementById('humChart'), {\n      type: 'line',\n      data: {\n        labels,\n        datasets: humDatasets\n      }\n    });\n  });\n&lt;\/script&gt;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u3067WordPress\u30da\u30fc\u30b8\u4e0a\u306b\u30012\u53f0\u5206\u306e\u6e29\u5ea6\u30fb\u6e7f\u5ea6\u30b0\u30e9\u30d5\u304c\u8868\u793a\u3055\u308c\u307e\u3059\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u6ce8\u610f\u70b9<\/h3>\n\n\n\n<p class=\"has-vivid-red-color has-text-color has-link-color wp-elements-295b8b8451a4bdfafcfb6cda0f6fb753 wp-block-paragraph\">\uff0a<strong>API\u30ad\u30fc\u306f\u63a8\u6e2c\u3055\u308c\u306b\u304f\u3044\u9577\u3044\u6587\u5b57\u5217\u306b\u3057\u3066\u304f\u3060\u3055\u3044<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">\u307e\u305f\u3001DHT22\u306f\u8aad\u307f\u53d6\u308a\u5931\u6557\u304c\u305d\u3053\u305d\u3053\u3042\u308b\u306e\u3067\u3001Raspberry Pi\u5074\u3067\u306f\u5931\u6557\u6642\u306b\u518d\u8a66\u884c\u3059\u308b\u8a2d\u8a08\u306b\u3059\u308b\u3068\u5b89\u5b9a\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u5b9f\u7528\u7684\u306b\u306f\u3001\u6e2c\u5b9a\u9593\u9694\u306f\u00a01\u5206\u301c5\u5206\u00a0\u304f\u3089\u3044\u304c\u304a\u3059\u3059\u3081\u3067\u3059\u3002DHT22\u306f\u9ad8\u983b\u5ea6\u6e2c\u5b9a\u306b\u306f\u5411\u304d\u307e\u305b\u3093\u3002\u304c\u3001DHT22\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\u300c5\u5206\u306b1\u56de\u9001\u4fe1\u3059\u308c\u3070\u3088\u3044\u306e\u3067\u30011\u5206\u9593\u9593\u3067\u6e2c\u5b9a\u3057\u3066\u3001\u305d\u306e\u5408\u8a08\u306e\u5e73\u5747\u5024\u3092\u9001\u308b\u300d\u3084\u308a\u65b9\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">1\u5206\u9593\u3060\u3051\u8907\u6570\u56de\u6e2c\u5b9a\u3057\u3066\u5e73\u5747\u3057\u30015\u5206\u306b1\u56de\u3060\u3051\u30b5\u30fc\u30d0\u30fc\u3078\u9001\u4fe1\u3059\u308b\u65b9\u5f0f\u306f\u3001DHT22\u3067\u3082\u5b9f\u7528\u7684\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code>5\u5206\u5468\u671f <\/code>\n<code>\u251c\u2500 \u6700\u521d\u306e1\u5206\u9593: 2\u301c3\u79d2\u3054\u3068\u306b\u6e2c\u5b9a <\/code>\n<code>\u2502 \u3000\u2514\u2500 \u7570\u5e38\u5024\u3084\u8aad\u307f\u53d6\u308a\u5931\u6557\u306f\u6368\u3066\u308b <\/code>\n<code>\u251c\u2500 \u5e73\u5747\u5024\u3092\u8a08\u7b97 <\/code>\n<code>\u251c\u2500 Fideafact.fideafact.fideafact.ddns.net\/sensor\/data\u3078\u9001\u4fe1 <\/code>\n<code>\u2514\u2500 \u6b8b\u308a\u7d044\u5206\u5f85\u6a5f<\/code><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">DHT22\u306f\u9ad8\u983b\u5ea6\u306b\u8aad\u3081\u306a\u3044\u306e\u3067\u3001<strong>2\u79d2\u672a\u6e80\u3067\u306f\u8aad\u307e\u306a\u3044<\/strong>\u65b9\u304c\u3044\u3044\u3067\u3059\u3002<br>1\u5206\u9593\u306a\u3089\u30012\u79d2\u3054\u3068\u3067\u6700\u592730\u56de\u30013\u79d2\u3054\u3068\u3067\u7d0420\u56de\u6e2c\u308c\u307e\u3059\u3002\u5b89\u5b9a\u6027\u91cd\u8996\u306a\u3089&nbsp;<strong>3\u79d2\u3054\u3068<\/strong>&nbsp;\u304c\u304a\u3059\u3059\u3081\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u9001\u308b\u30c7\u30fc\u30bf\u306f\u5e73\u5747\u5024\u306b\u52a0\u3048\u3066\u3001\u6e2c\u5b9a\u56de\u6570\u3082\u5165\u308c\u308b\u3068\u5f8c\u3067\u4fbf\u5229\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"device_id\": \"raspi-1\",\n  \"temperature\": 24.6,\n  \"humidity\": 53.2,\n  \"sample_count\": 20\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3055\u3089\u306b\u826f\u304f\u3059\u308b\u306a\u3089\u3001\u5358\u7d14\u5e73\u5747\u3088\u308a\u3082&nbsp;<strong>\u5916\u308c\u5024\u9664\u53bb\u3064\u304d\u5e73\u5747<\/strong>&nbsp;\u304c\u5411\u3044\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\u4f8b:\n1\u5206\u9593\u306720\u56de\u6e2c\u5b9a\n\u2193\n\u660e\u3089\u304b\u306b\u5909\u306a\u5024\u3092\u9664\u5916\n\u2193\n\u4e0a\u4e0b1\u301c2\u500b\u3092\u6368\u3066\u308b\n\u2193\n\u6b8b\u308a\u3092\u5e73\u5747\n\u2193\n5\u5206\u3054\u3068\u306b\u9001\u4fe1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">DHT22\u306f\u305f\u307e\u306b\u8aad\u307f\u53d6\u308a\u5931\u6557\u3084\u98db\u3073\u5024\u304c\u51fa\u308b\u306e\u3067\u3001\u3053\u306e\u65b9\u5f0f\u3060\u3068\u30b0\u30e9\u30d5\u304c\u304b\u306a\u308a\u6ed1\u3089\u304b\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u7d50\u8ad6\u3068\u3057\u3066\u306f\u3001<strong>DHT22\u3092\u305d\u306e\u307e\u307e\u4f7f\u3046\u306a\u3089\u300c3\u79d2\u3054\u3068\u306b1\u5206\u9593\u6e2c\u5b9a \u2192 \u5e73\u5747 \u2192 5\u5206\u3054\u3068\u9001\u4fe1\u300d\u304c\u73fe\u5b9f\u7684\u3067\u304a\u3059\u3059\u3081<\/strong>\u3067\u3059\u3002<br>\u30bb\u30f3\u30b5\u30fc\u3092SHT45\u306b\u5909\u3048\u308b\u5834\u5408\u3067\u3082\u3001\u3053\u306e\u5e73\u5747\u5316\u65b9\u5f0f\u306f\u6709\u52b9\u3067\u3059\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u53c2\u8003<\/h2>\n\n\n\n<pre class=\"wp-block-code has-luminous-vivid-orange-color has-pale-cyan-blue-background-color has-text-color has-background has-link-color wp-elements-26a93d10799e6e7ba264e890fb887176\"><code>import time\nimport traceback\nimport os\nimport sys\nimport board\nimport adafruit_dht\nimport requests\n\nSERVER_URL = \"https:\/\/fideafact.fideafact.fideafact.ddns.net\/sensor\/data\/sensor\"\nINTERVAL = 600\nLOCKFILE = \"\/tmp\/dht22.lock\"\n\n# \u591a\u91cd\u8d77\u52d5\u9632\u6b62\ndef check_lock():\n    if os.path.exists(LOCKFILE):\n        with open(LOCKFILE) as f:\n            old_pid = f.read().strip()\n        if old_pid and os.path.exists(f\"\/proc\/{old_pid}\"):\n            print(f\"\u65e2\u306b\u8d77\u52d5\u4e2d (PID {old_pid})\u3001\u7d42\u4e86\u3057\u307e\u3059\", flush=True)\n            sys.exit(1)\n    with open(LOCKFILE, \"w\") as f:\n        f.write(str(os.getpid()))\n\ndef cleanup_lock():\n    try:\n        os.remove(LOCKFILE)\n    except OSError:\n        pass\n\ncheck_lock()\n\ndef create_dht():\n    return adafruit_dht.DHT22(board.D4, use_pulseio=False)\n\ndht = create_dht()\nerror_count = 0\nMAX_RETRY = 3\n\ntry:\n    while True:\n        try:\n            print(\"\u6e2c\u5b9a\u958b\u59cb\", flush=True)\n\n            try:\n                temp = dht.temperature\n                humidity = dht.humidity\n                error_count = 0\n            except RuntimeError as e:\n                print(f\"\u8aad\u307f\u53d6\u308a\u30a8\u30e9\u30fc\uff08\u7d99\u7d9a\uff09: {e}\", flush=True)\n                error_count += 1\n            except OSError as e:\n                print(f\"DHT\/GPIO\u30a8\u30e9\u30fc\uff08\u7d99\u7d9a\uff09: {type(e).__name__}: {e}\", flush=True)\n                error_count += 1\n            else:\n                if temp is None or humidity is None:\n                    print(\"None\u306e\u305f\u3081\u9001\u4fe1\u3057\u306a\u3044\", flush=True)\n                else:\n                    print(f\"\u6e29\u5ea6: {temp:.1f}\u00b0C  \u6e7f\u5ea6: {humidity:.1f}%\", flush=True)\n                    payload = {\"temperature\": temp, \"humidity\": humidity}\n                    try:\n                        r = requests.post(SERVER_URL, json=payload, timeout=10)\n                        print(f\"\u9001\u4fe1\u7d50\u679c: HTTP {r.status_code}\", flush=True)\n                        print(f\"\u5fdc\u7b54\u672c\u6587: {r.text&#91;:300]}\", flush=True)\n                        r.raise_for_status()\n                    except requests.RequestException as e:\n                        print(f\"HTTP\u9001\u4fe1\u30a8\u30e9\u30fc\uff08\u7d99\u7d9a\uff09: {type(e).__name__}: {e}\", flush=True)\n\n            # \u9023\u7d9a\u30a8\u30e9\u30fc\u6642\u306f\u5373\u5ea7\u306b\u518d\u521d\u671f\u5316\uff08\u5f85\u6a5f\u305b\u305a\uff09\n            if error_count >= MAX_RETRY:\n                print(f\"\u9023\u7d9a{error_count}\u56de\u30a8\u30e9\u30fc \u2192 DHT\u518d\u521d\u671f\u5316\", flush=True)\n                try:\n                    dht.exit()\n                except Exception:\n                    pass\n                time.sleep(3)\n                dht = create_dht()\n                error_count = 0\n\n        except Exception:\n            print(\"\u60f3\u5b9a\u5916\u30a8\u30e9\u30fc:\", flush=True)\n            traceback.print_exc()\n\n        finally:\n            print(f\"{INTERVAL}\u79d2\u5f85\u6a5f\", flush=True)\n            time.sleep(INTERVAL)\n\nfinally:\n    cleanup_lock()\n    try:\n        dht.exit()\n    except Exception:\n        pass<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u5909\u66f4\u3002<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>5\u5206\u3054\u3068\u306b\u9001\u4fe1<\/strong><\/li>\n\n\n\n<li>\u9001\u4fe1\u524d\u306b&nbsp;<strong>1\u5206\u9593\u306712\u56de\u6e2c\u5b9a<\/strong><\/li>\n\n\n\n<li>\u6e2c\u5b9a\u9593\u9694\u306f&nbsp;5\u79d2<\/li>\n\n\n\n<li>None\u3001\u7bc4\u56f2\u5916\u3001\u8aad\u307f\u53d6\u308a\u30a8\u30e9\u30fc\u306f\u9664\u5916<\/li>\n\n\n\n<li>\u6b8b\u3063\u305f\u5024\u304b\u3089\u4e0a\u4e0b\u3092\u6368\u3066\u308b<\/li>\n\n\n\n<li>\u5e73\u5747\u5024\u3092\u9001\u4fe1<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-e38099910259c2a51f68ea16c0d9c46f\"><code>import time\nimport traceback\nimport os\nimport sys\nimport board\nimport adafruit_dht\nimport requests\n\nSERVER_URL = \"https:\/\/fideafact.fideafact.fideafact.ddns.net\/sensor\/data\/sensor\"\n\nSEND_INTERVAL = 300          # 5\u5206\u3054\u3068\u306b\u9001\u4fe1\nSAMPLE_COUNT = 12            # 1\u5206\u9593\u306712\u56de\u6e2c\u5b9a\nSAMPLE_INTERVAL = 5          # 5\u79d2\u3054\u3068\u306b\u6e2c\u5b9a\nLOCKFILE = \"\/tmp\/dht22.lock\"\n\nMAX_RETRY = 3\n\n# \u660e\u3089\u304b\u306b\u5909\u306a\u5024\u3092\u9664\u5916\u3059\u308b\u7bc4\u56f2\nTEMP_MIN = -40.0\nTEMP_MAX = 80.0\nHUM_MIN = 0.0\nHUM_MAX = 100.0\n\n\n# \u591a\u91cd\u8d77\u52d5\u9632\u6b62\ndef check_lock():\n    if os.path.exists(LOCKFILE):\n        with open(LOCKFILE) as f:\n            old_pid = f.read().strip()\n        if old_pid and os.path.exists(f\"\/proc\/{old_pid}\"):\n            print(f\"\u65e2\u306b\u8d77\u52d5\u4e2d (PID {old_pid})\u3001\u7d42\u4e86\u3057\u307e\u3059\", flush=True)\n            sys.exit(1)\n\n    with open(LOCKFILE, \"w\") as f:\n        f.write(str(os.getpid()))\n\n\ndef cleanup_lock():\n    try:\n        os.remove(LOCKFILE)\n    except OSError:\n        pass\n\n\ndef create_dht():\n    return adafruit_dht.DHT22(board.D4, use_pulseio=False)\n\n\ndef is_valid_reading(temp, humidity):\n    if temp is None or humidity is None:\n        return False\n\n    if not (TEMP_MIN &lt;= temp &lt;= TEMP_MAX):\n        return False\n\n    if not (HUM_MIN &lt;= humidity &lt;= HUM_MAX):\n        return False\n\n    return True\n\n\ndef trimmed_average(values):\n    \"\"\"\n    \u4e0a\u4e0b\u306e\u5024\u3092\u6368\u3066\u3066\u5e73\u5747\u3059\u308b\u3002\n    \u30c7\u30fc\u30bf\u6570\u304c\u591a\u3051\u308c\u3070\u4e0a\u4e0b2\u500b\u3001\u5c11\u306a\u3051\u308c\u3070\u4e0a\u4e0b1\u500b\u3092\u6368\u3066\u308b\u3002\n    \"\"\"\n    if not values:\n        return None\n\n    values = sorted(values)\n    n = len(values)\n\n    if n >= 8:\n        trim = 2\n    elif n >= 4:\n        trim = 1\n    else:\n        trim = 0\n\n    trimmed = values&#91;trim:n - trim] if trim > 0 else values\n\n    if not trimmed:\n        return None\n\n    return sum(trimmed) \/ len(trimmed)\n\n\ndef measure_for_one_minute(dht):\n    global_error_count = 0\n    readings = &#91;]\n\n    print(\"1\u5206\u9593\u306e\u6e2c\u5b9a\u958b\u59cb\", flush=True)\n\n    for i in range(SAMPLE_COUNT):\n        try:\n            temp = dht.temperature\n            humidity = dht.humidity\n\n            if is_valid_reading(temp, humidity):\n                readings.append({\n                    \"temperature\": temp,\n                    \"humidity\": humidity\n                })\n                print(\n                    f\"{i + 1}\/{SAMPLE_COUNT}: \u6e29\u5ea6 {temp:.1f}\u00b0C \u6e7f\u5ea6 {humidity:.1f}%\",\n                    flush=True\n                )\n            else:\n                print(\n                    f\"{i + 1}\/{SAMPLE_COUNT}: \u7570\u5e38\u5024\u306e\u305f\u3081\u9664\u5916 temp={temp}, humidity={humidity}\",\n                    flush=True\n                )\n\n        except RuntimeError as e:\n            print(f\"{i + 1}\/{SAMPLE_COUNT}: \u8aad\u307f\u53d6\u308a\u30a8\u30e9\u30fc\uff08\u7d99\u7d9a\uff09: {e}\", flush=True)\n            global_error_count += 1\n\n        except OSError as e:\n            print(f\"{i + 1}\/{SAMPLE_COUNT}: DHT\/GPIO\u30a8\u30e9\u30fc\uff08\u7d99\u7d9a\uff09: {type(e).__name__}: {e}\", flush=True)\n            global_error_count += 1\n\n        if i &lt; SAMPLE_COUNT - 1:\n            time.sleep(SAMPLE_INTERVAL)\n\n    temperatures = &#91;r&#91;\"temperature\"] for r in readings]\n    humidities = &#91;r&#91;\"humidity\"] for r in readings]\n\n    avg_temp = trimmed_average(temperatures)\n    avg_humidity = trimmed_average(humidities)\n\n    return avg_temp, avg_humidity, len(readings), global_error_count\n\n\ncheck_lock()\n\ndht = create_dht()\nerror_count = 0\n\ntry:\n    while True:\n        cycle_start = time.time()\n\n        try:\n            avg_temp, avg_humidity, valid_count, read_errors = measure_for_one_minute(dht)\n            error_count += read_errors\n\n            if avg_temp is None or avg_humidity is None:\n                print(\"\u6709\u52b9\u306a\u6e2c\u5b9a\u5024\u304c\u4e0d\u8db3\u3057\u3066\u3044\u308b\u305f\u3081\u9001\u4fe1\u3057\u307e\u305b\u3093\", flush=True)\n                error_count += 1\n            else:\n                print(\n                    f\"\u5e73\u5747\u5024: \u6e29\u5ea6 {avg_temp:.1f}\u00b0C \u6e7f\u5ea6 {avg_humidity:.1f}% \"\n                    f\"\u6709\u52b9\u6e2c\u5b9a\u6570 {valid_count}\/{SAMPLE_COUNT}\",\n                    flush=True\n                )\n\n                payload = {\n                    \"temperature\": round(avg_temp, 2),\n                    \"humidity\": round(avg_humidity, 2),\n                    \"sample_count\": valid_count\n                }\n\n                try:\n                    r = requests.post(SERVER_URL, json=payload, timeout=10)\n                    print(f\"\u9001\u4fe1\u7d50\u679c: HTTP {r.status_code}\", flush=True)\n                    print(f\"\u5fdc\u7b54\u672c\u6587: {r.text&#91;:300]}\", flush=True)\n                    r.raise_for_status()\n\n                    error_count = 0\n\n                except requests.RequestException as e:\n                    print(f\"HTTP\u9001\u4fe1\u30a8\u30e9\u30fc\uff08\u7d99\u7d9a\uff09: {type(e).__name__}: {e}\", flush=True)\n\n            if error_count >= MAX_RETRY:\n                print(f\"\u9023\u7d9a{error_count}\u56de\u30a8\u30e9\u30fc \u2192 DHT\u518d\u521d\u671f\u5316\", flush=True)\n                try:\n                    dht.exit()\n                except Exception:\n                    pass\n\n                time.sleep(3)\n                dht = create_dht()\n                error_count = 0\n\n        except Exception:\n            print(\"\u60f3\u5b9a\u5916\u30a8\u30e9\u30fc:\", flush=True)\n            traceback.print_exc()\n\n        finally:\n            elapsed = time.time() - cycle_start\n            wait_time = max(0, SEND_INTERVAL - elapsed)\n\n            print(f\"{wait_time:.0f}\u79d2\u5f85\u6a5f\", flush=True)\n            time.sleep(wait_time)\n\nfinally:\n    cleanup_lock()\n    try:\n        dht.exit()\n    except Exception:\n        pass<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u306e\u30b3\u30fc\u30c9\u3067\u306f\u30011\u30b5\u30a4\u30af\u30eb\u304c\u5408\u8a08\u3067\u7d045\u5206\u306b\u306a\u308a\u307e\u3059\u3002<br>\u3064\u307e\u308a&nbsp;<strong>\u7d041\u5206\u6e2c\u5b9a \u2192 \u5e73\u5747\u5024\u3092\u9001\u4fe1 \u2192 \u6b8b\u308a\u7d044\u5206\u5f85\u6a5f<\/strong>&nbsp;\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">DHT22\u306a\u3089&nbsp;SAMPLE_INTERVAL = 5&nbsp;\u306f\u304b\u306a\u308a\u5b89\u5168\u3067\u3059\u3002\u3082\u3063\u3068\u7d30\u304b\u304f\u3057\u305f\u3044\u5834\u5408\u3067\u3082\u3001DHT22\u3067\u306f&nbsp;2\u79d2\u672a\u6e80&nbsp;\u306b\u306f\u3057\u306a\u3044\u65b9\u304c\u3088\u3044\u3067\u3059\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u30b5\u30fc\u30d0\u30fc\u53d7\u3051\u53d6\u308b\u5074\u306e\u66f4\u306a\u308b\u52b9\u7387\u5316\u3000BEST\u30d0\u30fc\u30b8\u30e7\u30f3<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">fideafact.fideafact.fideafact.ddns.net\/sensor\/data\u3067\u53d7\u3051\u53d6\u3063\u305f\u30c7\u30fc\u30bf\u306fwordpres\u3067DB\u4fdd\u5b58\u30fb\u30b0\u30e9\u30d5\u8868\u793a\u3059\u308b\u5f62\u3067\u3059\u304c\u3002\u3053\u308c\u3092Wordpress\u30d7\u30e9\u30b0\u30a4\u30f3\u3067\u3059\u308b\u65b9\u6cd5\u3082\u3042\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>WordPress\u30d7\u30e9\u30b0\u30a4\u30f3\u5316\u3059\u308b\u65b9\u6cd5\u304c\u4e00\u756a\u304d\u308c\u3044<\/strong>\u3067\u3059\u3002<br>Raspberry Pi\u304b\u3089\u00a0<strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">https:\/\/fideafact.fideafact.fideafact.ddns.net\/sensor\/data\/wp-json\/dht22\/v1\/submit<\/mark><\/strong>\u00a0\u306bPOST\u3057\u3001WordPress\u5074\u306e\u30d7\u30e9\u30b0\u30a4\u30f3\u304c\u53d7\u4fe1\u30fbDB\u4fdd\u5b58\u30fb\u30b0\u30e9\u30d5\u8868\u793a\u307e\u3067\u62c5\u5f53\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u30d7\u30e9\u30b0\u30a4\u30f3\u3067\u3084\u308b\u5185\u5bb9\u306f\u3053\u306e3\u3064\u3067\u3059\u3002<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>1. REST API\u3067\u30c7\u30fc\u30bf\u53d7\u4fe1\n2. WordPress DB\u306b\u4fdd\u5b58\n3. \u30b7\u30e7\u30fc\u30c8\u30b3\u30fc\u30c9\u3067\u30b0\u30e9\u30d5\u8868\u793a<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">\u30d7\u30e9\u30b0\u30a4\u30f3\u69cb\u6210<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>wp-content\/plugins\/dht22-logger\/\n\u2514\u2500 dht22-logger.php<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">dht22-logger.php<\/h3>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-ccc0540c52f6d3b6e1d812ad0dcccb36\"><code>&lt;?php\n\/*\nPlugin Name: DHT22 Logger\nDescription: Receive DHT22 temperature\/humidity data and display charts.\nVersion: 1.0.0\n*\/\n\nif (!defined('ABSPATH')) {\n    exit;\n}\n\ndefine('DHT22_LOGGER_API_KEY', 'your-secret-key');\n\nregister_activation_hook(__FILE__, 'dht22_logger_activate');\n\nfunction dht22_logger_activate() {\n    global $wpdb;\n\n    $table = $wpdb->prefix . 'dht22_logs';\n    $charset_collate = $wpdb->get_charset_collate();\n\n    $sql = \"CREATE TABLE $table (\n        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n        device_id VARCHAR(64) NOT NULL DEFAULT 'default',\n        temperature FLOAT NOT NULL,\n        humidity FLOAT NOT NULL,\n        sample_count INT UNSIGNED DEFAULT 1,\n        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,\n        PRIMARY KEY (id),\n        KEY device_time (device_id, created_at)\n    ) $charset_collate;\";\n\n    require_once ABSPATH . 'wp-admin\/includes\/upgrade.php';\n    dbDelta($sql);\n}\n\nadd_action('rest_api_init', function () {\n    register_rest_route('dht22\/v1', '\/submit', &#91;\n        'methods' => 'POST',\n        'callback' => 'dht22_logger_submit',\n        'permission_callback' => '__return_true',\n    ]);\n\n    register_rest_route('dht22\/v1', '\/data', &#91;\n        'methods' => 'GET',\n        'callback' => 'dht22_logger_data',\n        'permission_callback' => '__return_true',\n    ]);\n});\n\nfunction dht22_logger_submit(WP_REST_Request $request) {\n    global $wpdb;\n\n    $params = $request->get_json_params();\n\n    if (($params&#91;'api_key'] ?? '') !== DHT22_LOGGER_API_KEY) {\n        return new WP_Error('forbidden', 'Invalid API key', &#91;'status' => 403]);\n    }\n\n    $temperature = isset($params&#91;'temperature']) ? floatval($params&#91;'temperature']) : null;\n    $humidity = isset($params&#91;'humidity']) ? floatval($params&#91;'humidity']) : null;\n\n    if ($temperature === null || $humidity === null) {\n        return new WP_Error('bad_request', 'temperature and humidity are required', &#91;'status' => 400]);\n    }\n\n    if ($temperature &lt; -40 || $temperature > 80 || $humidity &lt; 0 || $humidity > 100) {\n        return new WP_Error('bad_request', 'Value out of range', &#91;'status' => 400]);\n    }\n\n    $device_id = sanitize_text_field($params&#91;'device_id'] ?? 'default');\n    $sample_count = isset($params&#91;'sample_count']) ? intval($params&#91;'sample_count']) : 1;\n\n    $wpdb->insert(\n        $wpdb->prefix . 'dht22_logs',\n        &#91;\n            'device_id' => $device_id,\n            'temperature' => $temperature,\n            'humidity' => $humidity,\n            'sample_count' => $sample_count,\n            'created_at' => current_time('mysql'),\n        ],\n        &#91;'%s', '%f', '%f', '%d', '%s']\n    );\n\n    return &#91;\n        'ok' => true,\n        'id' => $wpdb->insert_id,\n    ];\n}\n\nfunction dht22_logger_data(WP_REST_Request $request) {\n    global $wpdb;\n\n    $hours = intval($request->get_param('hours') ?: 24);\n    if ($hours &lt; 1 || $hours > 168) {\n        $hours = 24;\n    }\n\n    $device_id = sanitize_text_field($request->get_param('device_id') ?: '');\n\n    $table = $wpdb->prefix . 'dht22_logs';\n\n    if ($device_id !== '') {\n        return $wpdb->get_results(\n            $wpdb->prepare(\n                \"SELECT device_id, temperature, humidity, sample_count, created_at\n                 FROM $table\n                 WHERE device_id = %s\n                   AND created_at >= DATE_SUB(NOW(), INTERVAL %d HOUR)\n                 ORDER BY created_at ASC\",\n                $device_id,\n                $hours\n            )\n        );\n    }\n\n    return $wpdb->get_results(\n        $wpdb->prepare(\n            \"SELECT device_id, temperature, humidity, sample_count, created_at\n             FROM $table\n             WHERE created_at >= DATE_SUB(NOW(), INTERVAL %d HOUR)\n             ORDER BY created_at ASC\",\n            $hours\n        )\n    );\n}\n\nadd_shortcode('dht22_chart', 'dht22_logger_chart_shortcode');\n\nfunction dht22_logger_chart_shortcode($atts) {\n    $atts = shortcode_atts(&#91;\n        'hours' => '24',\n    ], $atts);\n\n    $hours = intval($atts&#91;'hours']);\n    if ($hours &lt; 1 || $hours > 168) {\n        $hours = 24;\n    }\n\n    ob_start();\n    ?>\n    &lt;div style=\"max-width: 100%; margin: 20px 0;\">\n        &lt;canvas id=\"dht22TempChart\" height=\"120\">&lt;\/canvas>\n        &lt;canvas id=\"dht22HumChart\" height=\"120\" style=\"margin-top: 30px;\">&lt;\/canvas>\n    &lt;\/div>\n\n    &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\">&lt;\/script>\n    &lt;script>\n    (function () {\n        const hours = &lt;?php echo json_encode($hours); ?>;\n\n        fetch('&lt;?php echo esc_url(rest_url('dht22\/v1\/data')); ?>?hours=' + hours)\n            .then(response => response.json())\n            .then(rows => {\n                const devices = &#91;...new Set(rows.map(row => row.device_id))];\n\n                const colors = &#91;\n                    '#e53935',\n                    '#1e88e5',\n                    '#43a047',\n                    '#fb8c00',\n                    '#8e24aa'\n                ];\n\n                const labels = &#91;...new Set(rows.map(row => row.created_at))];\n\n                function buildDataset(field, labelSuffix) {\n                    return devices.map((device, index) => {\n                        const deviceRows = rows.filter(row => row.device_id === device);\n\n                        return {\n                            label: device + ' ' + labelSuffix,\n                            data: deviceRows.map(row => ({\n                                x: row.created_at,\n                                y: Number(row&#91;field])\n                            })),\n                            borderColor: colors&#91;index % colors.length],\n                            backgroundColor: colors&#91;index % colors.length],\n                            borderWidth: 2,\n                            tension: 0.25\n                        };\n                    });\n                }\n\n                new Chart(document.getElementById('dht22TempChart'), {\n                    type: 'line',\n                    data: {\n                        datasets: buildDataset('temperature', '\u6e29\u5ea6')\n                    },\n                    options: {\n                        parsing: false,\n                        responsive: true,\n                        scales: {\n                            x: {\n                                type: 'category',\n                                labels: labels,\n                                ticks: {\n                                    maxTicksLimit: 10\n                                }\n                            },\n                            y: {\n                                title: {\n                                    display: true,\n                                    text: '\u6e29\u5ea6 \u00b0C'\n                                }\n                            }\n                        }\n                    }\n                });\n\n                new Chart(document.getElementById('dht22HumChart'), {\n                    type: 'line',\n                    data: {\n                        datasets: buildDataset('humidity', '\u6e7f\u5ea6')\n                    },\n                    options: {\n                        parsing: false,\n                        responsive: true,\n                        scales: {\n                            x: {\n                                type: 'category',\n                                labels: labels,\n                                ticks: {\n                                    maxTicksLimit: 10\n                                }\n                            },\n                            y: {\n                                title: {\n                                    display: true,\n                                    text: '\u6e7f\u5ea6 %'\n                                },\n                                min: 0,\n                                max: 100\n                            }\n                        }\n                    }\n                });\n            });\n    })();\n    &lt;\/script>\n    &lt;?php\n    return ob_get_clean();\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Raspberry Pi\u5074\u306e\u9001\u4fe1\u5148<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Python\u5074\u306f\u3053\u306eURL\u306b\u9001\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-luminous-vivid-orange-color has-text-color has-link-color wp-elements-278635511e1c8cffd5acf16d3265dd08\"><code>SERVER_URL = \"https:\/\/fideafact.fideafact.fideafact.ddns.net\/sensor\/data\/wp-json\/dht22\/v1\/submit\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">payload\u306b\u306f&nbsp;api_key&nbsp;\u3068&nbsp;device_id&nbsp;\u3092\u5165\u308c\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-luminous-vivid-orange-color has-text-color has-link-color wp-elements-fd205fbcbdc32b39a9a19ad4b2121dc0\"><code>payload = {\n    \"device_id\": \"raspi-1\",\n    \"temperature\": round(avg_temp, 2),\n    \"humidity\": round(avg_humidity, 2),\n    \"sample_count\": valid_count,\n    \"api_key\": \"your-secret-key\"\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">2\u53f0\u76ee\u306f\u3053\u3046\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-luminous-vivid-orange-color has-text-color has-link-color wp-elements-5beb69ed00d7badccb64ffcc1e548e60\"><code>\"device_id\": \"raspi-2\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">\u30b0\u30e9\u30d5\u8868\u793a\u65b9\u6cd5<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">WordPress\u306e\u56fa\u5b9a\u30da\u30fc\u30b8\u3084\u6295\u7a3f\u306b\u3001\u3053\u308c\u3092\u8cbc\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-d726b01c5f2c7d669c5b69b1d267ef39\"><code>&#91;dht22_chart hours=\"24\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u904e\u53bb7\u65e5\u5206\u306a\u3089\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-6a450b9a2be6e66e38208f09844f05b9\"><code>&#91;dht22_chart hours=\"168\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u3053\u308c\u30672\u53f0\u5206\u306e\u6e29\u5ea6\u30fb\u6e7f\u5ea6\u304c\u540c\u3058\u30b0\u30e9\u30d5\u306b\u8868\u793a\u3055\u308c\u307e\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">API\u30ad\u30fc\u306e\u00a0your-secret-key\u00a0\u306f\u3001\u9577\u3044\u30e9\u30f3\u30c0\u30e0\u6587\u5b57\u5217\u306b\u5909\u3048\u3066\u304f\u3060\u3055\u3044\u3002<br><strong>\u4f8b\uff1adht22_9sK3xQ7mP2vL8nR4zA1bY6<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">\u300cFlask\u3067\u53d7\u3051\u53d6\u3063\u3066MySQL\u4fdd\u5b58\u300d\u3059\u308bpy\u30b3\u30fc\u30c9<\/p>\n\n\n\n<pre class=\"wp-block-code has-luminous-vivid-orange-color has-pale-cyan-blue-background-color has-text-color has-background has-link-color wp-elements-903ba876d47ee68686d5c417efeecd7e\"><code>import mysql.connector\n\napp = Flask(__name__)\n\ndef get_db():\n    return mysql.connector.connect(\n        host='localhost',\n        user='sensoruser',\n        password='ttnx3teb',\n        database='sensor_db'\n    )\n\n@app.route('\/sensor', methods=&#91;'POST'])\ndef receive():\n    data = request.json\n    conn = get_db()\n    cur = conn.cursor()\n    cur.execute(\n        \"INSERT INTO readings (temperature, humidity) VALUES (%s, %s)>\n        (data&#91;'temperature'], data&#91;'humidity'])\n    )\n    conn.commit()\n    conn.close()\n    return 'OK', 200\n\n@app.route('\/sensor\/data', methods=&#91;'GET'])\ndef get_data():\n    conn = get_db()\n    cur = conn.cursor()\n    cur.execute(\"\"\"\n        SELECT temperature, humidity, created_at\n        FROM readings\n        WHERE created_at > NOW() - INTERVAL 7 DAY\n        ORDER BY created_at ASC\n    \"\"\")\n    rows = cur.fetchall()\n    conn.close()\n    result = &#91;{'temperature': r&#91;0], 'humidity': r&#91;1], 'time': str(r&#91;2>\n    return {'data': result}\n\nif __name__ == '__main__':\n    app.run(host='0.0.0.0', port=5000)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u65b9\u5411\u6027\u3068\u3057\u3066\u306f\u300cFlask\u3067\u53d7\u3051\u53d6\u3063\u3066MySQL\u4fdd\u5b58\u300d\u306f\u3067\u304d\u307e\u3059\u3002<br>\u305f\u3060\u3057\u3001\u3053\u306e\u30b3\u30fc\u30c9\u306e\u307e\u307e\u3060\u3068&nbsp;<strong>\u69cb\u6587\u30a8\u30e9\u30fc\u3067\u8d77\u52d5\u3057\u307e\u305b\u3093<\/strong>\u3002\u3055\u3089\u306b\u3001WordPress\u3067DB\u4fdd\u5b58\u30fb\u8868\u793a\u3057\u305f\u3044\u5834\u5408\u306f\u3001<strong>WordPress\u30d7\u30e9\u30b0\u30a4\u30f3\u65b9\u5f0f\u306e\u65b9\u304c\u7ba1\u7406\u3057\u3084\u3059\u3044<\/strong>\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u4e3b\u306a\u554f\u984c\u3067\u3059\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Flask&nbsp;\u3068&nbsp;request&nbsp;\u306e import \u304c\u3042\u308a\u307e\u305b\u3093<\/li>\n\n\n\n<li>SQL\u6587\u304c\u9014\u4e2d\u3067\u58ca\u308c\u3066\u3044\u307e\u3059<br>VALUES (%s, %s)&gt;&nbsp;\u306e&nbsp;&gt;&nbsp;\u304c\u4e0d\u8981<\/li>\n\n\n\n<li>result&nbsp;\u306e\u884c\u304c\u9014\u4e2d\u3067\u58ca\u308c\u3066\u3044\u307e\u3059<br>str(r[2&gt;&nbsp;\u306b\u306a\u3063\u3066\u3044\u308b<\/li>\n\n\n\n<li>device_id&nbsp;\u304c\u306a\u3044\u306e\u30672\u53f0\u306eRaspberry Pi\u3092\u533a\u5225\u3067\u304d\u307e\u305b\u3093<\/li>\n\n\n\n<li>API\u30ad\u30fc\u8a8d\u8a3c\u304c\u306a\u3044\u306e\u3067\u8ab0\u3067\u3082\u6295\u7a3f\u3067\u304d\u3066\u3057\u307e\u3044\u307e\u3059<\/li>\n\n\n\n<li>DB\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u30b3\u30fc\u30c9\u306b\u76f4\u66f8\u304d\u3057\u3066\u3044\u307e\u3059<\/li>\n\n\n\n<li>\u3044\u307e\u8cbc\u3089\u308c\u305f\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u516c\u958b\u6271\u3044\u306b\u306a\u308b\u306e\u3067\u3001\u53ef\u80fd\u306a\u3089\u5909\u66f4\u3057\u305f\u65b9\u304c\u5b89\u5168\u3067\u3059<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u4fee\u6b63\u7248\u306e\u6700\u5c0f\u4f8b\u306f\u3053\u3046\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-9141c46d626430a08c653fe3c0f4d9d0\"><code>from flask import Flask, request, jsonify\nimport mysql.connector\nimport os\n\napp = Flask(__name__)\n\nAPI_KEY = os.environ.get(\"SENSOR_API_KEY\", \"change-this-key\")\n\ndef get_db():\n    return mysql.connector.connect(\n        host=\"localhost\",\n        user=\"sensoruser\",\n        password=os.environ.get(\"SENSOR_DB_PASSWORD\"),\n        database=\"sensor_db\"\n    )\n\n@app.route(\"\/sensor\", methods=&#91;\"POST\"])\ndef receive():\n    data = request.get_json(silent=True)\n\n    if not data:\n        return jsonify({\"error\": \"invalid json\"}), 400\n\n    if data.get(\"api_key\") != API_KEY:\n        return jsonify({\"error\": \"invalid api key\"}), 403\n\n    try:\n        device_id = str(data.get(\"device_id\", \"unknown\"))&#91;:64]\n        temperature = float(data&#91;\"temperature\"])\n        humidity = float(data&#91;\"humidity\"])\n        sample_count = int(data.get(\"sample_count\", 1))\n    except (KeyError, TypeError, ValueError):\n        return jsonify({\"error\": \"invalid data\"}), 400\n\n    if not (-40 &lt;= temperature &lt;= 80):\n        return jsonify({\"error\": \"temperature out of range\"}), 400\n\n    if not (0 &lt;= humidity &lt;= 100):\n        return jsonify({\"error\": \"humidity out of range\"}), 400\n\n    conn = get_db()\n    cur = conn.cursor()\n    cur.execute(\n        \"\"\"\n        INSERT INTO readings\n            (device_id, temperature, humidity, sample_count)\n        VALUES\n            (%s, %s, %s, %s)\n        \"\"\",\n        (device_id, temperature, humidity, sample_count)\n    )\n    conn.commit()\n    cur.close()\n    conn.close()\n\n    return jsonify({\"ok\": True}), 200\n\n\n@app.route(\"\/sensor\/data\", methods=&#91;\"GET\"])\ndef get_data():\n    conn = get_db()\n    cur = conn.cursor()\n    cur.execute(\n        \"\"\"\n        SELECT device_id, temperature, humidity, sample_count, created_at\n        FROM readings\n        WHERE created_at > NOW() - INTERVAL 7 DAY\n        ORDER BY created_at ASC\n        \"\"\"\n    )\n    rows = cur.fetchall()\n    cur.close()\n    conn.close()\n\n    result = &#91;\n        {\n            \"device_id\": r&#91;0],\n            \"temperature\": r&#91;1],\n            \"humidity\": r&#91;2],\n            \"sample_count\": r&#91;3],\n            \"time\": str(r&#91;4])\n        }\n        for r in rows\n    ]\n\n    return jsonify({\"data\": result})\n\n\nif __name__ == \"__main__\":\n    app.run(host=\"0.0.0.0\", port=5000)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">DB\u30c6\u30fc\u30d6\u30eb\u306f\u4f8b\u3048\u3070\u3053\u3046\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code has-vivid-red-color has-text-color has-link-color wp-elements-f1667c01cf2e858e4fd61d111d0090ad\"><code>CREATE TABLE readings (\n    id BIGINT AUTO_INCREMENT PRIMARY KEY,\n    device_id VARCHAR(64) NOT NULL,\n    temperature FLOAT NOT NULL,\n    humidity FLOAT NOT NULL,\n    sample_count INT DEFAULT 1,\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n    INDEX device_time (device_id, created_at)\n);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u305f\u3060\u3057\u3001\u7d50\u8ad6\u3068\u3057\u3066\u306f\u3053\u3046\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>WordPress\u3067\u30b0\u30e9\u30d5\u8868\u793a\u3060\u3051\u3057\u305f\u3044\n\u2192 Flask\u3067\u3082\u53ef\u80fd\n\nWordPress\u3067DB\u4fdd\u5b58\u30fb\u7ba1\u7406\u30fb\u56fa\u5b9a\u30da\u30fc\u30b8\u8868\u793a\u307e\u3067\u3057\u305f\u3044\n\u2192 WordPress\u30d7\u30e9\u30b0\u30a4\u30f3\u65b9\u5f0f\u304c\u304a\u3059\u3059\u3081<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Flask\u65b9\u5f0f\u306b\u3059\u308b\u3068\u3001WordPress\u3068\u306f\u5225\u306b Flask \u30b5\u30fc\u30d0\u30fc\u3001MySQL\u3001\u30ea\u30d0\u30fc\u30b9\u30d7\u30ed\u30ad\u30b7\u3001\u5e38\u99d0\u8a2d\u5b9a\u3092\u7ba1\u7406\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<br>WordPress\u30d7\u30e9\u30b0\u30a4\u30f3\u65b9\u5f0f\u306a\u3089&nbsp;wp-json&nbsp;\u3067\u53d7\u4fe1\u3057\u3066\u3001\u305d\u306e\u307e\u307eWordPress\u306eDB\u3068\u30b7\u30e7\u30fc\u30c8\u30b3\u30fc\u30c9\u3067\u30b0\u30e9\u30d5\u8868\u793a\u3067\u304d\u308b\u306e\u3067\u3001\u3053\u306e\u7528\u9014\u306b\u306f\u304b\u306a\u308a\u76f8\u6027\u304c\u3044\u3044\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u69cb\u6210\u3068\u3057\u3066\u306f\u30012\u53f0\uff081\u53f0\u3067\u3082\u8907\u6570\u53f0\u3067\u3082\uff09\u306e&nbsp;Raspberry Pi Zero W 2 + DHT22&nbsp;\u304b\u3089\u5b9a\u671f\u7684\u306b\u6e29\u6e7f\u5ea6\u3092\u6e2c\u5b9a\u3057\u3001\u5916\u90e8\u30b5\u30fc\u30d0\u30fc&nbsp;Fideafact.fideafact.fi [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[38,24,37,43,20,39,40,44],"class_list":["post-93","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-dht22","tag-https","tag-python","tag-43","tag-20","tag-39","tag-40","tag-44"],"_links":{"self":[{"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=\/wp\/v2\/posts\/93","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=93"}],"version-history":[{"count":2,"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=\/wp\/v2\/posts\/93\/revisions"}],"predecessor-version":[{"id":95,"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=\/wp\/v2\/posts\/93\/revisions\/95"}],"wp:attachment":[{"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=93"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=93"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fideafact.ddns.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=93"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}