先日、東京アプリによる給付について書きました が一応、ポイント申請してみました。今朝メールが届いたのでアプリで確認したら保有ポイントが11,000Pになっていた。申請してからポイントが付くまで1日半ほどでした。
で、d払いアプリなるものを入れて使うらしいとのことで、入れてポイントをみたら12,345円になっていた。限定123Pというのが分からないけど。それでも1,000ポイントより多い。この12345というのはサンプル画面なのか?
https://pic-garage.blogspot.com/
先日、東京アプリによる給付について書きました が一応、ポイント申請してみました。今朝メールが届いたのでアプリで確認したら保有ポイントが11,000Pになっていた。申請してからポイントが付くまで1日半ほどでした。
で、d払いアプリなるものを入れて使うらしいとのことで、入れてポイントをみたら12,345円になっていた。限定123Pというのが分からないけど。それでも1,000ポイントより多い。この12345というのはサンプル画面なのか?
東京都が実施する生活支援キャンペーンで、東京都が公式スマートフォンアプリ「東京アプリ」を通じて、現金ではなく 11,000ポイント(1ポイント = 1円相当)受け取れる給付制度です。2月2日からはじまった。
よくわからなかったのでchatGPTとチャットして色々と教えてもらったら、驚愕の事実が、、、(検証はしてないので間違いがあるかも)
まず、付与されたポイントは以下の民間のポイントサービスに1ポイント=1円で交換できるらしい。
しかし個人的にはこれらのポイントサービスは使ってない。昔からポイントカードとかは面倒で使ってないのです。例外はポイントサービスの元祖であるヨドバシのポイント、アマゾンのポイント、クレジットカードのポイントだけ。
chatGPTが言うにはdポイントはアマゾンと連携して使えるらしい。でもアマゾンギフトカードは買えないよ、と教えてくれた。手順は以下のような感じ。
以上、面倒な作業が続く。「スマホが使えない独居の高齢者に無理だね」ということをchatGPTに聞いたら、「そうですね、本当に困窮している人には届かない施策」とのこと。
事業費なども聞いたら、給付用に450億円で、これは支給対象者の約1/3分しかない。要するに、元々全員に配る(申請する)とは考えてない。また、給付額を含む総事業費が799億円とのことなので349億円がシステム構築、運用管理、宣伝費など。これらには職員の人件費は含まないようなので、それを含めたらもっとかかっている計算。
なんだかなぁ、と思った次第。個人的には残された時間を考えると極力手間のかかることに時間を使いたくない、と思う今日この頃。でもサーバの混雑が解消したころに申請すると思う。
サクッと作ろうと思っていた温度ロガーですが、昨年の9月から始めてようやく完成。製作記事がふっとんで気力回復がイマイチなのでここまで。
特徴は次のような感じ。
# 温度ロガー設定ファイル # 例) # SSID mySSID # PW myPassWord # Interval 0 (0:1秒, 1:10秒, 2:30秒, 3:1分, 4:5分, 5:10分) # SSID mySSID PW myPassWord Interval 0
//---------------------------------------------------------------------------------------
// '26.01.31 naka
// ver.0 '25.09.14 naka
// ESP32 2ch温度ロガー(小型液晶に時刻も表示)
//
// ・測定の正確な日時はWiFi経由のntpサーバから取得
// ・microSDのsetup.txtファイルに平文でWiFiのSSID,Password 及び測定時間間隔の
// デフォルトの番号を記載(0:1秒, 1:10秒, 2:30秒, 3:1分, 4:5分, 5:10分)
// 例)SSID mySSID
// PW myPassWord
// Interval 0
// ・時間間隔は電源投入後にタクトスイッチでも変更可能(5秒経過すると測定を開始)
// ・WiFiがない環境で使う際は、タクトスイッチを押しながら電源オン
// ・WiWi設定があっても繋がらない場合には、複数回トライして諦める
// ・WiWiがない場合、或いは何度トライして繋がらない場合には日時を26年1月1日00:00:00とする
// ・ログはmicroSD内にタイムスタンプ付のcsvファイルとして格納する
// ・ファイル名が重複する場合にはファイル名に追番が付く
// ・WiFiに繋がない、繋がらない、ntpサーバに繋がらない際の日時は"2026-01-01 00:00:00"となる
// ・測定は指定した時刻が時間間隔で正時になったとき
// 例)10秒毎なら0秒、10秒、20秒…のとき、1分毎なら毎分0秒のとき
// ・スリープから1秒毎の割り込みで目覚めて正時になったか確認(再びスリープ)
//---------------------------------------------------------------------------------------
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP32Time.h>
#include <SD.h>
#include "FS.h"
#include "SPIFFS.h"
#include "esp_adc_cal.h"
ESP32Time rtc;
#define SD_CS 16 // SD card chip select
#define TACT_SW 25 // タクトスイッチ(WiFi未使用指示、測定時間間隔セット用)
const int SENSOR_PIN1 = 32; // 温度センサMCP9700Aの出力ピンを接続したADCピン
const int SENSOR_PIN2 = 33; // 温度センサMCP9700Aの出力ピンを接続したADCピン
esp_adc_cal_characteristics_t adc_chars;
#define SETUP_FILE "/setup.txt"
#include <FaBoLCDmini_AQM0802A.h>
FaBoLCDmini_AQM0802A lcd;
// microSDのsetupファイルに記載されているものが設定される
char ssid[24];
char password[24];
int interval;
int interval_i = 0;
const int interval_tbl[] = {1,10,30,60,300,600}; // 測定間隔(秒)
const int interval_tbl_size = 6;
char LogFile[64]; // 記録用のcsvファイル名(タイムスタンプから自動作成)
void setup()
{
char msg[17];
struct tm timeinfo;
char logfilename[64];
pinMode(TACT_SW, INPUT);
pinMode(SENSOR_PIN1, ANALOG);
pinMode(SENSOR_PIN2, ANALOG);
analogReadResolution(12); // 分解能12bit
analogSetAttenuation(ADC_11db);
// ADCキャリブレーション
esp_adc_cal_characterize(
ADC_UNIT_1, // GPIO32?39
ADC_ATTEN_DB_11, // 0?3.3V
ADC_WIDTH_BIT_12,
1100, // デフォルトVref(mV)
&adc_chars
);
// モニタLCD設定
SetupLCD();
delay(1000);
// setupファイルを読み、WiFiのssid,password、測定間隔のデフォルトを取得
if (!SD.begin(SD_CS, SPI, 24000000)) {
dispLCD_msg("microSD failed "," ");
while(true);
}
read_setup_file(SETUP_FILE);
bool wifi_flag = false;
if (digitalRead(TACT_SW)==LOW) {
dispLCD_msg("WiFi dosen't use"," ");
while(digitalRead(TACT_SW)==LOW);
}
else {
dispLCD_msg("Connecting WiFi "," ");
if (wifi_connect()) {
wifi_flag = true;
}
else {
dispLCD_msg("Connect failed "," ");
delay(1000);
}
}
delay(1000);
if (wifi_flag) {
// WiFi接続に成功した場合、NTPサーバに接続し、時刻設定
configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
int loopcnt = 0;
while (!getLocalTime(&timeinfo)) {
dispLCD_msg("Failed get time ","Retrying ... ");
if (++loopcnt>5) { // 念のため5回繰り返してダメなら抜ける
wifi_flag = false;
break;
}
delay(500);
}
dispLCD_msg(" "," ");
wifi_disconnect(); // 以降はWiFi未接続にする
}
// 起動時にSWが押されていたか、WiFi接続に失敗か、ntpサーバからの時刻取得に失敗した場合は下記の日付と時刻設定
if (!wifi_flag) {
rtc.setTime(1767225600); // 2026-01-01 00:00:00
}
// 測定時間間隔の設定(5秒無操作で戻ってくる)
set_interval();
// ログファイル名を決めるためにタイムスタンプ取得
getLocalTime(&timeinfo);
sprintf(logfilename, "%02d%02d%02d_%02d%02d%02d.csv",(timeinfo.tm_year + 1900)%100, timeinfo.tm_mon + 1, timeinfo.tm_mday,timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
// WiFiに繋がない場合、時刻情報を取得できないためタイムスタンプのファイル名が同じになることを防ぐ。
get_unique_filename("",logfilename,LogFile,sizeof(LogFile));
// 測定開始メッセージ
dispLCD_msg("Start "," measurement");
// 1,000,000us = 1sのタイマー設定
esp_sleep_enable_timer_wakeup(1000000);
}
void loop()
{
// 温度を測定してログファイルに書き出す
measurement(interval);
// ライトスリープ(タイマー割り込みで1秒毎に目覚める)
esp_light_sleep_start();
}
void set_interval() {
disp_interval(interval_i); // 現在の設定時間を表示
int prevmsec = millis();
while ((millis() - prevmsec)<5000) { // 5秒反応が無ければ時間設定を抜ける
if (digitalRead(TACT_SW)==LOW) {
interval_i++;
prevmsec = millis();
if (interval_i>=interval_tbl_size) interval_i = 0;
disp_interval(interval_i); // 現在の設定時間を表示
while (digitalRead(TACT_SW)==LOW) {} // SWが離されるまで待つ
delay(20); //チャタリング対策
prevmsec = millis();
}
}
interval = interval_tbl[interval_i];
return;
}
void disp_interval(int i) {
int time = interval_tbl[i];
char msg[20];
if (time<60)
sprintf(msg,"%11d(sec)",time);
else
sprintf(msg,"%11d(min)",time/60);
dispLCD_msg("set interval ",msg);
}
void measurement(int period) {
char yymmddhhmmss[17],hhmmss[10],timestamp[17];
struct tm timeinfo;
getLocalTime(&timeinfo);
// 測定する時間なのか確認(割り込みは1秒毎なので)
bool flag = false;
if (period==1) flag = true;
else if (period==10 && timeinfo.tm_sec%10==0) flag = true;
else if (period==30 && timeinfo.tm_sec%30==0) flag = true;
else if (period==60 && timeinfo.tm_sec==0) flag = true;
else if (period==120 && timeinfo.tm_sec==0 && timeinfo.tm_min%2==0) flag = true;
if (flag) {
sprintf(timestamp,"%02d:%02d:%02d",timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
sprintf(yymmddhhmmss, "%02d%02d%02d %s",(timeinfo.tm_year + 1900)%100, timeinfo.tm_mon + 1, timeinfo.tm_mday, timestamp);
float temp1 = temp_sensing(SENSOR_PIN1);
float temp2 = temp_sensing(SENSOR_PIN2);
char buff1[6],buff2[6],buff[20];
dtostrf(temp1,4,1,buff1);
dtostrf(temp2,4,1,buff2);
sprintf(buff, "%4s%cC , %4s%cC",buff1,0xDF,buff2,0xDF);
dispLCD_msg(yymmddhhmmss,buff);
write_logfile(timestamp,buff1,buff2); // microSDに書き込み
}
}
float temp_sensing(const int sensor) {
float offset;
uint32_t voltage_mV = 0;
const int N = 100;
for ( int i = 0 ; i < N ; i++ ) {
int adcRaw = analogRead(sensor);
// ADC値 → 電圧(mV)(補正済み)
voltage_mV += esp_adc_cal_raw_to_voltage(adcRaw, &adc_chars);
}
// 電圧 → 温度(℃)
float temperatureC = ((float)voltage_mV/N - 500.0) / 10.0;
// 温度センサ毎の校正
if (sensor==SENSOR_PIN1) offset = -0.9;
else offset = -1.2;
return temperatureC + offset;
}
void dispLCD_msg(char msg1[],char msg2[]) {
lcd.clear();
lcd.setCursor(0, 0); // Col,Raw
lcd.print(msg1);
lcd.setCursor(0, 1); // Col,Raw
lcd.print(msg2);
}
void write_logfile(char* timestamp, char* buff1,char* buff2){
char buff[32];
File outputFile = SD.open(LogFile,FILE_APPEND);
sprintf(buff,"%s,%s,%s",timestamp,buff1,buff2);
outputFile.println(buff);
outputFile.close();
}
void SetupLCD() {
delay(150);
lcd.begin();
lcd.command(0x38);
delay(1);
lcd.command(0x39);
delay(1);
lcd.command(0x14);
delay(1);
lcd.command(0x71);
delay(1);
// lcd.command(0x51); // 5V
lcd.command(0x56); // 3.3V
delay(2);
lcd.command(0x6c);
delay(300);
lcd.command(0x38);
delay(1);
lcd.command(0x01);
delay(2);
lcd.command(0x0c);
delay(2);
}
// Wifi接続
bool wifi_connect() {
char msg[128];
bool connected = false;
for (int i=0;i<3;i++) { // WiFi接続、3回繰り返す
WiFi.begin(ssid, password);
long int StartTime=millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
if ((StartTime+5000) < millis()) break; // 5秒待って繋がらないときは諦める
}
if (WiFi.status() == WL_CONNECTED) {
IPAddress ip = WiFi.localIP();
sprintf(msg,"%d.%d.%d.%d",ip[0], ip[1], ip[2], ip[3]);
dispLCD_msg("Connected IP ",msg);
connected = true;
break;
}
delay(100);
}
if (connected)
return true;
else {
wifi_disconnect();
delay(100);
return false;
}
}
void wifi_disconnect() {
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
int read_setup_file(char* fileName) {
char buff[128];
char key[128],val[128];
File setupFile = SD.open(fileName,FILE_READ);
if (setupFile) {
while (readLine(setupFile,buff)>=0) {
if (buff[0]!='#') {
sscanf(buff,"%s %s",&key,&val);
if (strcmp(key,"SSID")==0) {
strcpy(ssid,val);
}
else if (strcmp(key,"PW")==0) {
strcpy(password,val);
}
else if (strcmp(key,"Interval")==0) {
int ival;
sscanf(val,"%d",&ival);
if (ival>=0 && ival<interval_tbl_size) { // 異常値チェック
interval_i = ival;
}
}
}
}
setupFile.close();
}
return 0;
}
// microSDから1行読み取る
int readLine(File fp, char *buff){
int i = 0;
if(!fp.available()) {
return -1;
}
while (fp.available()) {
char c = fp.read();
if (c=='\r');
else if (c=='\n') break;
else buff[i++] = c;
}
buff[i] = 0;
return i;
}
/**
* 重複しないファイル名を生成する関数 (ChatGPTに書いてもらった)
* @param fs_prefix マウントポイント (例: "/spiffs")
* @param base_name 元のファイル名 (例: "data.txt")
* @param out_path 結果を格納するバッファ
* @param max_len バッファの最大サイズ
*/
void get_unique_filename(const char* fs_prefix, const char* base_name, char* out_path, size_t max_len) {
char temp_path[128];
char name_part[64];
char ext_part[16];
// 拡張子を探す
const char *dot = strrchr(base_name, '.');
if (dot) {
size_t name_len = dot - base_name;
strncpy(name_part, base_name, name_len);
name_part[name_len] = '\0';
strcpy(ext_part, dot);
} else {
strcpy(name_part, base_name);
ext_part[0] = '\0';
}
// 最初は元の名前でチェック
snprintf(out_path, max_len, "%s/%s", fs_prefix, base_name);
struct stat st;
int counter = 1;
// ファイルが存在し続ける間、ループ
while (SD.exists(out_path)) {
// "パス/ベース名 + 数字 + 拡張子" を組み立て
snprintf(out_path, max_len, "%s/%s_%d%s", fs_prefix, name_part, counter, ext_part);
counter++;
// 無限ループ防止(必要に応じて)
if (counter > 999) break;
}
}
//---------------------------------------------------------------------------------------
// EOF
//---------------------------------------------------------------------------------------
TOF(Time Of Fright;飛行時間)センサというものを試してみました。VL6180というチップを使ったTOF050C(50cmまで)と、VL53L0Xを使ったTOF200C(2mまで)の2つのモジュールを購入。とても薄くて小さいモジュールで、何かに組み込むにはよい感じです。
(追記 26.02.05) アリエクのショップには50cmまでと書かれていたが、よく調べたらVL6180は定格100mmまでで、実用範囲で200~250mmらしい。
TOFセンサについては下記のサイト参照。
#include "Wire.h"
#include "VL6180X.h"
VL6180X sensor;
void setup() {
Serial.begin(9600);
Wire.begin();
sensor.init();
sensor.configureDefault();
sensor.setTimeout(500);
}
void loop() {
Serial.print(sensor.readRangeSingleMillimeters());
Serial.println("mm");
delay(1000);
}
最終的に非接触のスイッチを作ろうと思っています。数十センチ離れていても反応するようにしたいので、フォトリフレクタではちょっと力不足。シャープの測距センサはちょっとでかいのでこれを試してみました。常時動かすのでセンサの寿命が気になるところですが。
10年前に発売された機種だけど、普段かみさんがYoutubeを見たり、雑誌を読んだり、ネットを見るにはまだまだ十分使える。昨日だったかはセキュリティアップデートも配信された。まだ見捨てられてない模様。
家から持ち出すことは殆どなく、常時ACアダプタに繋いで使うと言っているのでしばらくはこのまま。この先、不便になることがあったら買い替えるかも知れない。
校正というのか、温度を無理やりオフセットして手元にあるシンワの温度計と同じになるようにしました。写真はすべて同じ19.4℃を表示していますが偶々です。0.1~0.2℃位は動きます。そもそも単純にオフセットしてよいものなのか? 温度によって変わりそうな気もするけど。そこまで精度を求めるものでもないので、これで完了とします。
float temp_sensing(const int sensor) {
float offset;
uint32_t voltage_mV = 0;
const int N = 100;
for ( int i = 0 ; i < N ; i++ ) {
int adcRaw = analogRead(sensor);
// ADC値 → 電圧(mV)(補正済み)
voltage_mV += esp_adc_cal_raw_to_voltage(adcRaw, &adc_chars);
}
// 電圧 → 温度(℃)
float temperatureC = ((float)voltage_mV/N - 500.0) / 10.0;
// 温度センサ毎の校正
if (sensor==SENSOR_PIN1) offset = -0.9;
else offset = -1.2;
return temperatureC + offset;
}
需要があるか不明ですが、回路図とスケッチ全体はコードを少しキレイにしてから公開します。