Type-C 15W 3A 18650 Lithium Battery Charger Module DC-DC Step Up Booster Fast Charge UPS Power Supply 5,9,12V
WaveShare, Solar Power Manager Module (D), Supports 6V~24V Solar Panel and Type-C Power Adapter, 5V/3A Regulated Output | Solar Power Manager (D)、基板モジュール,コネクタはしっかりしたターミナルブロック、USB-PDのUSB-Cコネクタ装備
これで、ソーラーパネル→バッテリーチャージャー→Raspberry Pi の連携は劇的に改善することになったが、カメラなども含めて24時間常時稼働させるにはパワーが足りない。
#include <Arduino.h>
#include <TinyWireS.h>
#include <EEPROM.h>
#include <TimeLib.h>
// ==== ピン定義 ====
const int SDA_PIN = 0; // PB0 (固定)
const int SCL_PIN = 2; // PB2 (固定)
const int kPower = 1; // PB1 (pin 6)
const int pilotLamp = 4; // PB4 (pin 3)
const int keepAlivePin = 3; // PB3 (pin 2)
#define I2C_SLAVE_ADDRESS 0x40
// ==== 状態管理 ====
const int kModeWaiting = 1;
const int kModeShouldOff = 2;
const int kModeShouldOn = 3;
int mode = kModeWaiting;
time_t eventArrivalTime = 0;
int nextTurnOnMinutes = 59;
int nextTurnOffSeconds = 30;
unsigned long lastKeepAliveTime = 0;
int lastKeepAliveState = LOW;
const unsigned long keepAliveTimeoutMs = 30000;
volatile byte errorCode = 0;
volatile bool i2cCommandReceived = false;
volatile byte receivedData[2];
volatile byte receivedIndex = 0;
// ==== プロトタイプ宣言 ====
void receiveEvent(uint8_t howMany);
void requestEvent();
void blink(int durationMs);
void setup() {
pinMode(pilotLamp, OUTPUT);
digitalWrite(pilotLamp, LOW);
pinMode(kPower, OUTPUT);
digitalWrite(kPower, HIGH); // 電源ONでスタート
pinMode(keepAlivePin, INPUT);
setTime(0, 0, 0, 1, 1, 2025); // 仮の時刻
TinyWireS.begin(I2C_SLAVE_ADDRESS);
TinyWireS.onReceive(receiveEvent);
TinyWireS.onRequest(requestEvent);
// EEPROMから復旧
byte storedOffSec = EEPROM.read(0);
byte storedOnMin = EEPROM.read(1);
if (storedOffSec == 0xFF || storedOffSec == 0 || storedOffSec > 120 ||
storedOnMin == 0xFF || storedOnMin == 0 || storedOnMin > 180) {
nextTurnOffSeconds = 30;
nextTurnOnMinutes = 59;
EEPROM.update(0, nextTurnOffSeconds);
EEPROM.update(1, nextTurnOnMinutes);
} else {
nextTurnOffSeconds = storedOffSec;
nextTurnOnMinutes = storedOnMin;
}
}
time_t prevTime = 0;
void loop() {
TinyWireS_stop_check();
time_t nowTime = now();
// LED表示
if (prevTime != nowTime) {
if ((nowTime % (errorCode ? 1 : 5)) == 0) {
blink(errorCode ? 100 : 50);
}
prevTime = nowTime;
}
// KeepAlive監視
int currentKeepAliveState = digitalRead(keepAlivePin);
if (currentKeepAliveState != lastKeepAliveState) {
lastKeepAliveState = currentKeepAliveState;
lastKeepAliveTime = millis();
}
if ((millis() - lastKeepAliveTime) > keepAliveTimeoutMs) {
mode = kModeShouldOff;
eventArrivalTime = nowTime;
errorCode = 1;
}
// モード制御
switch (mode) {
case kModeWaiting:
break;
case kModeShouldOff:
if (nowTime >= eventArrivalTime) {
mode = kModeShouldOn;
eventArrivalTime = nowTime + nextTurnOnMinutes * 60;
digitalWrite(kPower, LOW); // 電源OFF
}
break;
case kModeShouldOn:
if (nowTime >= eventArrivalTime) {
mode = kModeWaiting;
eventArrivalTime = 0;
digitalWrite(kPower, HIGH); // 電源ON
}
break;
}
// I2Cコマンド処理
if (i2cCommandReceived) {
i2cCommandReceived = false;
nextTurnOffSeconds = receivedData[0];
nextTurnOnMinutes = receivedData[1];
EEPROM.update(0, nextTurnOffSeconds);
EEPROM.update(1, nextTurnOnMinutes);
eventArrivalTime = nowTime + nextTurnOffSeconds;
mode = kModeShouldOff;
}
delay(50);
}
// ==== I2C受信イベント ====
void receiveEvent(uint8_t howMany) {
receivedIndex = 0;
while (TinyWireS.available() && receivedIndex < 2) {
receivedData[receivedIndex++] = TinyWireS.receive();
}
if (receivedIndex == 2) {
i2cCommandReceived = true;
}
}
// ==== I2Cリクエスト(マスターから読まれたとき) ====
void requestEvent() {
TinyWireS.send(errorCode);
}
// ==== LED点滅 ====
void blink(int durationMs) {
digitalWrite(pilotLamp, HIGH);
delay(durationMs);
digitalWrite(pilotLamp, LOW);
delay(200);
}
最近の発注例。こういう極小基板も面付けして100mmx100mmに納めると安く作れる。ただし、製品製作時のチェックで各モジュールが異なる機能部品であると判断されれば追加料金がかかってしまう。これは、検査エンジニアの判断によることが多い。