Last Updated on 2026-07-05 by researcher
以前に作ったトイレ照明用のセンサーが5年ほど経過したところでWiFi不調により誤動作するようになってしまった。
ちなみに、今までESP8266/32で作ってきたものは結果として数年程度の運用で廃棄したものがほとんど。なので、もう実運用で使う気にはなれない...
Raspberry Pi Zero 2Wでも数年程度の運用でWiFiに不具合が出たものが複数あったりしてWiFiの安定性や耐久性についてはあまり芳しくないようだが内臓WiFiが壊れたとしてもUSBのWiFiアダプターで代用できるため故障しても簡単に治せる。ということでオーバースペックではあるが安定性や耐久性を考慮しRaspberry Pi Zero 2Wで作り直してみた。
今回も汎用LEDによる光センサーにしたかったがGPIOの入力インピーダンスの関係で外付け回路なしでは厳しそうだったため入手しやすく安価なGY-302(BH1750)に変更し、人を検出するために使用していた赤外線距離センサーが高価かつ入手性も悪いため下記投稿の自作の赤外線近接センサーに変更した。
自作の赤外線近接センサーは入手性の良い安い汎用部品で作れるし赤外線LEDの発光強度にもよるが赤外線反射率の高い物体なら1メートル程度離れていても検出できて照明の光でも誤動作しない。
なお、トイレの部屋の間取りや設置物の関係で人がいなくても近接センサーがオンしてしまうときはR2(220Ω)を470Ωなどより大きな抵抗にする必要があるので設定等で感度調整できるように改良したいところではある。
ついでに...トイレは毎日必ず使うものなのでその回数の記録とか一人暮らしの人のための見守り機能への対応などもいいかもしれない。
実験中、Raspberry PiのGPIOから赤外線LEDを直接駆動すると他のGPIOの入力が誤動作してしまうことがあったので2N7000経由で駆動するようにしてみた。
2N7000に発振防止用のゲート抵抗を入れるかどうかでしばし悩んだが抵抗無しでも発振することなく綺麗な波形が確認できたことや2N7000の入出力容量が小さいこととGPIOの出力インピーダンスが比較的高めなため抵抗は省略してしまったが...発振防止用の抵抗については理想駆動回路上での机上の理論だけが蔓延してるような気がするものの...ググったりAIに聞いたりするかぎり必要だと言う意見ばかりなので盲信者からのツッコミを避けるためのお守りとしても発振防止用の抵抗は入れておいたほうがいいのかもしれない。v(-_-;)
【設置】
以前の投稿では座ってる人を検出するために便器の横に設置していたが、センサー部を入口側に向けるようにトイレ奥の壁の中央付近に両面テープ等で貼り付けるのがお勧め。
便座のフタが開いてるときだけセンサーが隠れるように設置すると近接センサーがフタの開閉に反応しフタが開いてるときは消灯しなくなるので何かと便利。自動開閉するトイレにはお勧めの設置方法であるがフタが開くことで環境光センサーの光量が低下するためフタが開いてるときの照度で閾値(lux_threshold)を設定する必要がある。
トイレの照明は、TP-LINKのL510EというLED電球がお勧め。リモート操作&明るさの調整&点灯時に徐々に明るくなど夜中の目にもやさしい機能があってお手頃価格かつアマゾン等で普通に購入できる。
【アマゾンで購入した部品】
オーディオファン 赤外線センサー IR受信モジュール リモコン 受光部 など 電子工作 8個セット \733
5個 GY-302 光強度センサーモジュール BH1750FVI BH1750 3V-5V デュポンケーブル30ピン付き for Arduino AVR用 [\999]
Raspberry Pi Zero/Zero W プロトタイプ基板 [\346]
Geekworm Raspberry Pi Zero 2 W ヒートシンク、10mmアルミ合金 ヒートシンク (C296) [\999]
※その他の部品は秋月電子で購入。
【Raspberry Piの設定】
1. I2Cを有効化する。
|
1 2 3 4 |
sudo raspi-config -> 3 Interface Options -> I5 I2C -> <Yes> |
2. I2Cの通信速度の設定
|
1 2 3 |
/boot/firmware/config.txt or /boot/config.txt dtparam=i2c_arm=on,i2c_arm_baudrate=400000 |
【ダウンロード(必要なソース一式)】
wclight.zip
【必要なライブラリ(上記ダウンロードに含まれている)】
Raspberry PiでFANをPWM制御する。(自作ライブラリ版)
【必要なコマンド】
TP-LINK Tapo P105/P110M のKlapプロトコル対応版 (Windows/Linux)
【コンパイル】
|
1 2 3 |
#!/bin/sh gcc wclight.cpp rpio.cpp bcm_host.c -o wclight -lstdc++ |
【インストール】
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#!/bin/sh INSTALL_DIR=$(cd $(dirname $0) && pwd) PROGRAM_NAME=wclight PROGRAM_PATH=${INSTALL_DIR}/${PROGRAM_NAME} PROGRAM_OPTS="" SERVICE_NAME=${PROGRAM_NAME} SERVICE_PATH=/etc/systemd/system/${SERVICE_NAME}.service if [ -f ${SERVICE_PATH} ]; then systemctl stop ${SERVICE_NAME} systemctl disable ${SERVICE_NAME} fi echo "[Unit]" >${SERVICE_PATH} echo "Description=Toilet Light Controller" >>${SERVICE_PATH} echo "After=local-fs.target" >>${SERVICE_PATH} echo "ConditionPathExists=${INSTALL_DIR}" >>${SERVICE_PATH} echo >>${SERVICE_PATH} echo "[Service]" >>${SERVICE_PATH} echo "ExecStart=${PROGRAM_PATH} ${PROGRAM_OPTS}" >>${SERVICE_PATH} echo "Restart=always" >>${SERVICE_PATH} echo "Type=simple" >>${SERVICE_PATH} echo >>${SERVICE_PATH} echo "[Install]" >>${SERVICE_PATH} echo "WantedBy=multi-user.target" >>${SERVICE_PATH} systemctl daemon-reload systemctl enable ${SERVICE_NAME} systemctl start ${SERVICE_NAME} systemctl status ${SERVICE_NAME} |
【照明制御スクリプト (tapo2用)】
|
1 2 3 4 5 6 7 8 9 |
#!/bin/bash TAPO=/*****/tapo2 DEVICE=192.168.XXX.XXX USER=************* PSWD=************* $TAPO $DEVICE $USER $PSWD $1 echo [$?] $TAPO $DEVICE $1 |
【コンフィグ】
|
1 2 3 |
lux_threshold=15 delay_light_off=30 light_ctrl_cycle=10 |
【ソースコード】
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
/* wclight.cpp - Toilet Light Controller Copyright (c) 2026 Sasapea's Lab. All right reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #include <errno.h> #include <time.h> #include <unistd.h> #include <sys/stat.h> #include "rpio.h" #include "irps.h" #include "twi.h" #include "bh1750.h" #include "state.h" #define PIN_PIR 10 #define PIN_STATUS 21 #define PIN_IRINP 6 #define PIN_IROUT 13 #define LUX_THRESHOLD 15 /* lux */ #define DELAY_LIGHT_OFF 30 /* sec */ #define LIGHT_CTRL_CYCLE 10 /* sec */ #define INTERVAL 300 /* ms */ static TWI twi; static BH1750 als((IOBUS*)&twi); static IRPS ps(PIN_IRINP, PIN_IROUT); static int lux_threshold = LUX_THRESHOLD; static int delay_light_off = DELAY_LIGHT_OFF * 1000; static int light_ctrl_cycle = LIGHT_CTRL_CYCLE * 1000; static char conf_path[1024]; static char script[1024]; static char* script_arg; void config(const char* filepath) { static struct timespec last; struct stat fs; if (stat(filepath, &fs) == 0) { if (memcmp(&last, &fs.st_mtim, sizeof(fs.st_mtim)) != 0) { last = fs.st_mtim; FILE* fp; if ((fp = fopen(filepath, "r")) != NULL) { char line[256]; while (fgets(line, sizeof(line), fp) != NULL) { int len = strlen(line) - 1; while ((len > 0) && (line[len] <= ' ')) line[len--] = 0; char* p = strchr(line, '='); if (p) { *p++ = 0; if (strcmp(line, "lux_threshold") == 0) lux_threshold = atoi(p); else if (strcmp(line, "delay_light_off") == 0) delay_light_off = atoi(p) * 1000; else if (strcmp(line, "light_ctrl_cycle") == 0) light_ctrl_cycle = atoi(p) * 1000; } } fclose(fp); } fprintf(stdout, "lux_threshold = %d lux\n", lux_threshold); fprintf(stdout, "delay_light_off = %d sec\n", delay_light_off / 1000); fprintf(stdout, "light_ctrl_cycle = %d sec\n", light_ctrl_cycle / 1000); } } } int control(bool on) { snprintf(script_arg, 8, on ? "on" : "off"); int rv = system(script); if (rv) { fprintf(stdout, "system(\"%s\") = %d\n", script, rv); fflush(stdout); } return rv; } void usage(void) { fprintf(stderr, "Toilet Light Controller, Version 1.00\n"); fprintf(stderr, "Copyright (C) 2026, Sasapea's Lab\n"); fprintf(stderr, "\n"); fprintf(stderr, "options: -d device ... I2C device name (\"/dev/i2c-1\")\n"); } int main(int argc, char **argv) { const char* name = "/dev/i2c-1"; int rv; opterr = 0; while ((rv = getopt(argc, argv, "d:")) != -1) { switch (rv) { case 'd': name = optarg; break; default: usage(); fprintf(stderr, "\ninvalid option: %c\n", optopt); return -1; } } while (optind < argc) { usage(); fprintf(stderr, "\ninvalid option: %s\n", argv[optind++]); return -1; } if ((rv = twi.begin(name)) == -1) printf("Error: TWI::begin(%s) = %s\n", name, strerror(errno)); else { if ((rv = RPIO::begin()) == -1) printf("Error: RPIO::begin() = %s\n", strerror(errno)); else { /* setup */ snprintf(conf_path, sizeof(conf_path), "%s.conf", argv[0]); script_arg = script + snprintf(script, sizeof(script) - 8, "%s.sh ", argv[0]); RPIO::pinMode(PIN_PIR, INPUT, PULL_DOWN); RPIO::pinMode(PIN_STATUS, OUTPUT); ps.begin(); /* main loop */ State<bool> psstat(false); State<bool> light(false); time_t detect = -1; time_t swctrl = RPIO::millis() - light_ctrl_cycle; struct timespec cycle = RPIO::clock(); while (1) { /* Load Config */ config(conf_path); /* PIR Sensor */ if (RPIO::digitalRead(PIN_PIR)) { /* Ambient Light Sensor */ int lux = -1; if (als.start(BH1750_ONE_TIME_H_RESOLUTION_MODE2)) lux = als.lux() >> BH1750_FIXED_POINT_NBITS; if (lux >= lux_threshold) fprintf(stdout, "PIR (%d)\n", lux); else { detect = RPIO::millis(); if (lux != -1) fprintf(stdout, "PIR (%d-)\n", lux); else fprintf(stdout, "PIR (?)\n"); } } /* Proximity Sensor */ if (detect != -1) { if (psstat.update(ps.detect())) fprintf(stdout, "PS %s\n", psstat.current() ? "ON" : "OFF"); if (psstat.currnt()) detect = RPIO::millis(); } /* Auto Light OFF */ if ((detect != -1) && (RPIO::millis() - detect >= delay_light_off)) detect = -1; /* Status LED Control */ if (light.update(detect != -1)) { fprintf(stdout, "LIGHT %s\n", light.current() ? "ON" : "OFF"); RPIO::digitalWrite(PIN_STATUS, light.current() ? HIGH : LOW); swctrl = RPIO::millis() - light_ctrl_cycle; } /* Flush Log Output */ fflush(stdout); /* Light Control */ if (RPIO::millis() - swctrl >= light_ctrl_cycle) { swctrl += light_ctrl_cycle; control(light.current()); } /* Cycle Delay */ RPIO::delay(INTERVAL, &cycle); } } twi.end(); } return rv; } |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/* state.h - State Change Manegment Copyright (c) 2026 Sasapea's Lab. All right reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #pragma once template<typename T> class State { public: State(T state) : _current(state) { } bool update(T state) { bool changed = _current != state; _current = state; return changed; } T current(void) { return _current; } private: T _current; }; |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/* iobus.h - Peripheral I/O Bus Interface Copyright (c) 2026 Sasapea's Lab. All right reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #pragma once #include <stddef.h> class IOBUS { public: int write(int addr, const void* buf, size_t len) { return writeAndRead(addr, buf, len, nullptr, 0); } int read(int addr, void* buf, size_t len) { return writeAndRead(addr, nullptr, 0, buf, len); } virtual int writeAndRead(int addr, const void* wbuf, size_t wlen, void* rbuf, size_t rlen) = 0; }; |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
/* twi.h - I2C Library for Linux Copyright (c) 2026 Sasapea's Lab. All right reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #pragma once #include <stdbool.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/i2c-dev.h> #include <linux/i2c.h> #include "iobus.h" /* Setting for Raspberry Pi [/boot/firmware/config.txt] dtparam=i2c_arm=on,i2c_arm_baudrate=400000 */ class TWI : public IOBUS { public: static constexpr __u16 A10 = 0x8000; TWI(void) : _fd(-1), _flags(0) { } virtual ~TWI(void) { end(); } int begin(const char* name, bool tenbit = false) { end(); _flags = tenbit ? I2C_M_TEN : 0; return _fd = open(name, O_RDWR); } void end(void) { if (_fd != 0) { close(_fd); _fd = -1; } } int writeAndRead(int addr, const void* wbuf, size_t wlen, void* rbuf, size_t rlen) override { struct i2c_msg msgs[2]; struct i2c_rdwr_ioctl_data data = { .msgs = msgs, .nmsgs = 0 }; __u16 flags = _flags; if ((flags & I2C_M_TEN) || (addr & ~0x007F)) { flags |= I2C_M_TEN; addr &= 0x03FF; } if (wbuf && wlen) { msgs[data.nmsgs ].addr = addr; msgs[data.nmsgs ].flags = flags; msgs[data.nmsgs ].len = wlen; msgs[data.nmsgs++].buf = (__u8*)wbuf; } if (rbuf && rlen) { msgs[data.nmsgs ].addr = addr; msgs[data.nmsgs ].flags = flags | I2C_M_RD; msgs[data.nmsgs ].len = rlen; msgs[data.nmsgs++].buf = (__u8*)rbuf; } return ioctl(_fd, I2C_RDWR, &data); } private: int _fd; __u16 _flags; }; |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
/* BH1750.h - Light Sensor Library for Rohme BH1750 Copyright (c) 2026 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _BH1750_H #define _BH1750_H #include <stdint.h> #include <stdbool.h> #include "iobus.h" #include "rpio.h" typedef enum { BH1750_CONTINUOUSLY_H_RESOLUTION_MODE, BH1750_CONTINUOUSLY_H_RESOLUTION_MODE2, BH1750_CONTINUOUSLY_L_RESOLUTION_MODE, BH1750_ONE_TIME_H_RESOLUTION_MODE, BH1750_ONE_TIME_H_RESOLUTION_MODE2, BH1750_ONE_TIME_L_RESOLUTION_MODE, } BH1750_MODE; #define BH1750_DEFAULT_SLAVE_ADDRESS 0x23 #define BH1750_DEFAULT_MTREG_VALUE 69 // this value range (31 - 254) #define BH1750_DEFAULT_ACCURACY 120 // this value range (96 - 144) #define BH1750_FIXED_POINT_NBITS 4 class BH1750 { private: typedef enum : uint8_t { POWER_DOWN = 0x00, POWER_ON = 0x01, RESET = 0x07, CONTINUOUSLY_H_RESOLUTION_MODE = 0x10, CONTINUOUSLY_H_RESOLUTION_MODE2 = 0x11, CONTINUOUSLY_L_RESOLUTION_MODE = 0x13, ONE_TIME_H_RESOLUTION_MODE = 0x20, ONE_TIME_H_RESOLUTION_MODE2 = 0x21, ONE_TIME_L_RESOLUTION_MODE = 0x23, CHANGE_MEASUREMENT_TIME_H_BIT = 0x40, CHANGE_MEASUREMENT_TIME_L_BIT = 0x60, } INSTRUCTIONS; IOBUS* _iobus; uint8_t _addr; INSTRUCTIONS _cmode; uint8_t _fppos; uint8_t _mtreg; uint16_t _ctime; uint16_t _dtime; uint16_t _start; uint16_t _result; uint32_t millis(void) { return RPIO::millis(); } void delay(uint32_t ms) { RPIO::delay(ms); } bool write(INSTRUCTIONS inst) { return _iobus->write(_addr, &inst, sizeof(inst)) != -1; } bool read(void) { uint8_t data[2]; if (_iobus->read(_addr, data, sizeof(data)) == -1) return false; _result = ((uint16_t)data[0] << 8) | data[1]; _fppos = ((_cmode & 0x03) == 0x01 ? 1 : 0); return true; } bool measurement(INSTRUCTIONS mode) { // Change Measurement Time if (_mtreg) { if (!write((INSTRUCTIONS)(CHANGE_MEASUREMENT_TIME_H_BIT | ((_mtreg >> 5) & 0x07)))) return false; if (!write((INSTRUCTIONS)(CHANGE_MEASUREMENT_TIME_L_BIT | (_mtreg & 0x1F)))) return false; } // Start Measurement if (!write(mode)) return false; _start = millis(); _cmode = mode; _dtime = (mode & 0x02 ? 24 : 180); // TYP 16 : 120, MAX 24 : 180 _ctime = (_mtreg ? _dtime << 1 : _dtime); _mtreg = 0; // One Time Measurement mode ? if (mode & ONE_TIME_H_RESOLUTION_MODE) { delay(_ctime); if (!read()) return false; // NACK ? } return true; } bool power(bool on) { return write(on ? POWER_ON : POWER_DOWN); } public: BH1750(IOBUS* iobus, uint8_t addr = BH1750_DEFAULT_SLAVE_ADDRESS) : _iobus(iobus) , _addr(addr) , _cmode(POWER_DOWN) , _fppos(0) , _mtreg(BH1750_DEFAULT_MTREG_VALUE) , _ctime(0) , _dtime(0) , _start(0) , _result(0) { } virtual ~BH1750(void) { stop(); } bool reset(void) { return power(true) ? write(RESET) : false; } void mtreg(int val = 0) { val += BH1750_DEFAULT_MTREG_VALUE; if (val < 31) val = 31; else if (val > 254) val = 254; _mtreg = val; } bool start(BH1750_MODE mode = BH1750_CONTINUOUSLY_H_RESOLUTION_MODE2) { const INSTRUCTIONS MODES[] = { CONTINUOUSLY_H_RESOLUTION_MODE, CONTINUOUSLY_H_RESOLUTION_MODE2, CONTINUOUSLY_L_RESOLUTION_MODE, ONE_TIME_H_RESOLUTION_MODE, ONE_TIME_H_RESOLUTION_MODE2, ONE_TIME_L_RESOLUTION_MODE, }; return measurement(MODES[mode]); } bool stop(void) { return power(false); } uint32_t lux(uint8_t accuracy = BH1750_DEFAULT_ACCURACY) { if (accuracy < 96) accuracy = 96; else if (accuracy > 144) accuracy = 144; if (BH1750_FIXED_POINT_NBITS > 0) return ((uint32_t)_result << (+ BH1750_FIXED_POINT_NBITS - _fppos)) * 100 / accuracy; else return ((uint32_t)_result >> (- BH1750_FIXED_POINT_NBITS + _fppos)) * 100 / accuracy; } bool handle(void) { // Continuously Measurement mode ? if (_cmode & CONTINUOUSLY_H_RESOLUTION_MODE) { if ((uint16_t)((uint16_t)millis() - _start) >= _ctime) { _start += _ctime; _ctime = _dtime; return read(); } } return false; } }; #endif |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
/* irps.cpp - Infrared Proximity Sensor Library Copyright (c) 2026 Sasapea's Lab. All right reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. */ #pragma once #include <stdint.h> #include <stdbool.h> #include <time.h> #include "rpio.h" #define IRPS_DATA 0xA5 #define IRPS_TON 600 #define IRPS_TOFF 900 class IRPS { public: IRPS(pin_size_t input, pin_size_t output) : _input(input), _output(output) { } void begin(void) { RPIO::pinMode(_input, INPUT, PULL_UP); RPIO::digitalWrite(_output, LOW); _off = RPIO::pinMode(_output, OUTPUT); /* Setup PWM: 38KHz, 1/3 duty, no-invert, no-output */ _on = RPIO::analogWrite(_output, 38000, 1, 3, false, false); } bool detect(uint8_t data = IRPS_DATA) { uint8_t send = data; uint8_t recv = 0; struct timespec clock = RPIO::clock(); for (uint8_t i = 0; i < 8; ++i, send >>= 1) { RPIO::pinFunction(_output, send & 1 ? _on : _off); RPIO::delayMicroseconds(IRPS_TON, &clock); recv = (recv << 1) | !RPIO::digitalRead(_input); RPIO::pinFunction(_output, _off); RPIO::delayMicroseconds(IRPS_TOFF, &clock); } return data == recv; } private: pin_size_t _input; pin_size_t _output; PinFunc _off; PinFunc _on; }; |





