OmniAICreator/Qiita-1.07M huggingface dataset:
【UE5】【修正版】Character Movement Componentを使わずにルートモーションする

:::note info
以前書いた[【UE4】Character Movement Componentを使わずにルートモーションする](https://qiita.com/Rinderon/items/36e72c9c3d0b05af12bf)…の修正版となります。
:::

# やりたいこと

- ルートモーションを使いたい。
- だが、Character Actorクラス＋Character Movement Componentで作るほど大げさにしたくない。
- 普通のActor (またはPawn)＋Skeletal Mesh Componentでサクッとやりたい。
- Blueprintで使えるノードが欲しい。

# 以前の記事との違い

この記事は、以前書いた[【UE4】Character Movement Componentを使わずにルートモーションする](https://qiita.com/Rinderon/items/36e72c9c3d0b05af12bf)…の修正版となります。

以前の記事では、```UAnimInstance::ConsumeExtractedRootMotion()```を使ってルートモーションを抽出する方法を紹介しましたが、この方法では Animation Blueprint Linkingや Post Process Anim Blueprintを使っている場面に対応できません。```USkeletalMeshComponent::ConsumeRootMotion()```の内部でこれらに対応するコードが書かれているので、この関数を使うことで、この問題を回避できます。

# C++ソース例
以前の記事の場合と違い、UAnimInstanceを直接使う必要はないので、Blueprint Function Libraryに関数を記述することにします。

```cpp:MyBlueprintFunctionLibrary.h
UCLASS()
class UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
	
public:

	// このフレームのルートモーションによるDelta Transformを取得する
	UFUNCTION(BlueprintCallable, Category = "My Blueprint Function Library|Animation")
	static UPARAM(DisplayName = "DeltaTransform") FTransform ConsumeRootMotion(USkeletalMeshComponent * InMeshComp);
};
```

```cpp:MyBlueprintFunctionLibrary.cpp
FTransform UMyBlueprintFunctionLibrary::ConsumeRootMotion(USkeletalMeshComponent* InMeshComp)
{
	if (IsValid(InMeshComp))
	{
		// Skeletal Mesh Componentにルートモーションを計算(消費=consume)させる
		FRootMotionMovementParams Params = InMeshComp->ConsumeRootMotion();
		if (Params.bHasRootMotion)
		{
			// ワールド座標系に変換してreturnする
			return InMeshComp->ConvertLocalRootMotionToWorld(Params.GetRootMotionTransform());
		}
	}

	return FTransform::Identity;
}
```

# Blueprintでの使用例

C++側でWorld座標系のDelta Transformに変換済みなので、シンプルに```AddActorWorldTransform```に渡すだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/0bd68561-764d-4ed0-841d-32629f487306.png)
明日の勤務メンバーは誰がいるのかスマホで確認したい

# こんにちは

翌日の仕事のメンバーは誰かな、と気になる日が度々発生するので
日付を入力したら誰が勤務・休日なのかを教えてもらうツールを作ろう！
ついでに動物の画像も送ってもらって癒してもらおう！
そんな感じで「LINE Bot」というワードをつい最近知ったデジタル初心者が
作ってみました。


# ①使用ツール
・Make
・LINE Bot
・Googleスプレッドシート

# ②完成したもの

日付を入力したら誰が勤務・休日なのかを教えてもらえるツールです。
以下３点は完成したツールの静止画・動画・Makeシナリオとなります。

### LINE画面（静止画）
![Screenshot_20250423-015643.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/6e606b24-8c59-4dfb-bab3-fd5f3d268226.png)

### LINE画面（動画）
![g8mdz-wozix.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/cf654efb-6bd4-4bfa-9d00-4277bc20b554.gif)


### Makeシナリオ
![LINEbot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/9e6b6866-d9c0-4874-ba68-2005cabc6401.png)

# ③手順
### 使用API
・[Cats](https://api.thecatapi.com/v1/images/search"Cats")
ランダムで猫動画を表示するAPI。

こちらのQiita記事を参考にさせていただきました。　↓
ありがとうございます！
[無料で使える (癒やされたいだけの) 公開APIリスト: ねこ、いぬ、キツネ、柴犬、ジブリ](https://qiita.com/e99h2121/items/6d5cc72679f43aa37be2"無料で使える癒やされたいだけの公開APIリスト:ねこ、いぬ、キツネ、柴犬、ジブリ")

### １：Googleスプレッドシートにシフト表を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/c8fab75d-ae38-4aed-9de2-3aeebeb19ee2.png)
日付とメンバー名、出勤の場合は勤務時間が12時～21時だったら（12-21）と記入、休日の場合は（休み）と表記しました。

### ２：Google sheets(Search Rows) とLINE（Send a Reply Message）を作成

Google sheets
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/22e9b2ff-9adf-4bb4-b087-a076c6acb672.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/48753fc0-cc13-4734-b588-d11febaa2b59.png)
先程入力したGoogleスプレッドシートを選びます。

LINE
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/b80b8fae-2c06-4e7f-a299-de441cdbc6e4.png)
Messagesのところで返信してもらいたいメンバー全員の名前を選びます。

### ３：HTTP（Make a request）を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/81a20a2d-e390-4356-904e-6f853b5c397b.png)
これで可愛い猫ちゃんたちの画像が出ます。楽しみです。


### ４：JSON（Parse　JSON）を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/66fc6e8d-5717-49c8-8052-d406e2451cc6.png)

### ５：LINE（Send a Reply Message）の中身追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4050504/e257b214-4b22-494c-add7-ee9737d9ffed.png)
Typeを「Image」に変更！！この設定で猫の画像が出るようになります。

# あとがき
今回が初めてのLINE Bot作成でしたが、序盤に苦戦したせいで時間がかかってしまったので、Qiitaに掲載されている記事をかなり参考にして作成いたしました。なのでなぜこの項目を選ぶのか、などまだまだ理解出来ていないのが現状です。もっと頑張らねば！難しかったけれど、使いこなせるようになったらもっと楽しくなるだろうなと思いました。

なんとか形だけでも作成出来たのは先輩方の記事のおかげです。
大変お世話になりました。ありがとうございます！


2025/04/29  
・冒頭の内容を削除・修正しました。
・LINE動画追加しました。
・手順の画像に補足説明を追記しました。
・LINE Botなど正式名称を修正しました。
ハッカソン個人備忘録㉞：「サブちゃん日記」から「さぶちゃん日記」へ！PRの修正対応フロー（ローカル作業）

## はじめに
GitHub上のプルリクエストにて、以下のような指摘を受けました：

> タイトル「サブちゃん日記」を「さぶちゃん日記」に変更してください。

この内容をローカルで修正して反映する手順を以下に示します。対象ブランチは `feature/login-flow` です。

GitHub上のプルリクエストで指摘された内容に対して、ローカル環境で修正作業を行う手順をまとめています。

---

## 1. 現在のブランチを確認

```bash
git branch
```
出力例：
```
* feature/login-flow
  main
```

`feature/login-flow` にいることを確認。

---

## 2. リモートの最新状態を取得

```bash
git pull origin feature/login-flow
```

出力例：
```
Already up to date.
```
→ リモートとの同期が完了。

---

## 3. 対象ファイルをエディタで開く

```bash
code src/app/page.tsx
```
※ VS Code を使用している場合。使用エディタに応じて変更してください。

---

## 4. タイトルの修正

`src/app/page.tsx` 内のタイトル部分を以下のように変更：

```diff
- サブちゃん日記
+ さぶちゃん日記
```

---

## 5. Git に変更を反映

```bash
git add src/app/page.tsx
git commit -m "fix: タイトルを『さぶちゃん日記』に変更"
git push origin feature/login-flow
```

---

## 6. GitHub上で変更を確認

GitHubのプルリクエスト画面を開き、修正内容が反映されていることを確認。

---

## まとめ
このように、プルリクエストの指摘に対する対応は、

1. ローカル環境での修正
2. コミットとプッシュ
3. GitHubでの確認

という流れで行うとスムーズです。チーム開発では小さな修正も丁寧に対応していくことが大事だと思っています...！
FinOps Certified Practitioner の資格を取得してみました 2025年4月

# FinOps Certified Practitioner を取得した話

  
## 今回取得した資格名
FinOps Certified Practitioner Certification 
（発行主体：FinOps Foundation, a Linux Foundation program）


取得しようとおもったきっかけ：
普段はオンプレミス仮想製品を扱っているのですが、最近はやはりどこにいってもクラウドの話が出てきます。
中には"クラウドファースト"を標榜する人々も増えている中で、
オンプレ＝高い、遅い、古い
クラウド＝安い、早い、うまい
みたいな感覚論が先行していることを痛感するシーンが非常に多い…。

そのシーンを解決する策を模索し、どちらが良い/悪いではなく、正しく最適化するためには…と調べていく中でFinOpsというフレームワークがあることを知りました。
そこからせっかく資格があるなら受けてみようと思い立ったのがきっかけとなります。

![スクリーンショット 2025-04-24 16.06.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895754/d4555aa0-103f-4dc1-a139-0f171c67b95c.png)


## 取得までのプロセス
**１日目**
１, FinOps Foundationの公式サイトで、ラーニングコース＆試験のセットを購入。
　https://learn.finops.org/page/finops-certified-practitioner
　　- ラーニングコースのみ
　　- 試験のみ
　　- ラーニングコース＆試験
　　- ラーニングコース＆試験＆別資格試験バンドル版
　等のコースを選択して購入する形になります。
　自分はここで、"ラーニングコース＆試験" を購入。（キャンペーンコードをLinkedinの公式で拾ったので、375$で購入…@2025.04）
 ![スクリーンショット 2025-04-24 16.11.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895754/9fe3b0e4-c882-49ae-adc9-67113ad4d6d1.png)

　↓
　↓
**２日目〜１４日目**
２, ラーニングコース
　フレームワークの重要な要素を解説するようなテキストを読み進めていくスタイル。
　たまーに練習問題が挟まっている。
　テキストで大きな流れを把握した後は、公式が出しているフレームワークのガイドブックみたいなものも見ておくのがよい。
　いかんせんALL Englishなので、Google翻訳を駆使して読み進めること２週間。

　トレーニングコースのカリキュラム
　　- Introduction
　　- What is FinOps?
　　- FinOps Teams & Culture
　　- Personas & Motivations
　　- Anatomy of the Cloud Bill
　　- Adopting & Maturing FinOps
　　- FinOps Framework
　　- FinOps Domains & Capabilities
　　- Data in the Path
　　- Inform Phase
　　- Optimize Phase
　　- Operate Phase
　　- Resources & Review

　参考になるサイト：
　https://www.finops.org/framework/
　https://cloud.google.com/learn/what-is-finops
　https://www.cloudzero.com/blog/finops/
　https://www.youtube.com/watch?v=UcnHCjp20YQ
　↓
　↓
**１５日目**
３, 試験
　こちらもALL English。
　一応ブラウザの翻訳機能は使えるみたいだが、用語的に意味不明になって問題文を読み取れないので英語のまま。
　60分で50問の出題となっていて、基本的には1問1答。合格点は75%。
　（購入日から12ヶ月以内に3回受験することができるので、落ちてもめげずにチャレンジしましょう！）
　↓
　↓
**１６日目**
４, コミュニティへの参加申請、Linkedinでの自慢
　Badgeが発行されます。
　まだJapanの組織は編成されたばかりということもあり、Eventの機会も少ないようですね。。ぜひ参加していこうとおもいます


## 感想
FinOpsについての理解度はかなりしっかり深まります。
ツールや方式というよりは、「組織のあるべき」「行動のあるべき」が見えてくるので、非常に腹落ちする内容でした。
一部AzureやAWSの用語も出てくるので、環境を実際に触っていないにしても、ふわっとクラウドなんたるかはわかっていないと厳しいかも。（というかそれを知っている前提じゃないと意味がないはずの試験）
製品に特化した試験ではなく、フレームワークや考え方にまつわる試験なので、内容のテイストはITILとか、PMBOKに近いかも。
少し落ち着いたら勉強した内容自分なりにまとめてみようかと思います。
【CloudFront × WAF × Lambda@Edge】IP制限より先にBasic認証が出てしまう問題の解決メモ

## はじめに

CloudFront + Lambda@EdgeでのBasic認証 + WAFでのアクセス制御 という構成で、**「エラー403より先にベーシック認証のポップアップが出る？」という現象**に遭遇しました。
これについての原因と対処方法をメモとしてまとめておきます。

## 本記事で扱う内容

- CloudFrontでIP制限（WAF）とBasic認証（Lambda@Edge）を併用したときの問題
- ベーシック認証がWAFの前に出てしまうように見える原因
- カスタムエラーレスポンス設定による403レスポンスのすり替わり
- 正しく403が出るようにするための設定変更

## 構成概要

以下のような構成で運用していました。

- **CloudFront**  
  - S3（SPA）オリジン + API Gatewayオリジン
- **WAF**  
  - 許可されたIP以外は BLOCK（403）
- **Lambda@Edge**  
  - S3オリジンに対して Basic認証を実装（Vierwer Requestイベントで実行）

### やりたいこと

1. 許可IPのみアクセス許可（WAFがBLOCK）
2. 通った人だけベーシック認証（Lambda@Edgeが401を返す）

## 起きていた問題

意図と反して、**WAFで弾かれるはずのリクエストでもベーシック認証のポップアップが出る**という現象が発生。

- **WAFのログ** → 正しく BLOCK（403）が記録されている  
- **ブラウザのDevTools** → 401 Unauthorized が返っている  
- **Lambda@Edgeのログ** → WAFブロックされたはずのリクエストが到達してる？
## 原因

### CloudFrontの「エラーページ」の設定が原因

CloudFrontでは「WAFの403」も「オリジンからの403」も**区別なく**扱われるということで、

**403 が返ってきたら → S3の index.html を返す**
という設定があると
CloudFrontは「WAFの403」にも同じように反応し、**エラーページを取得するために再度オリジンへアクセスしようとしてしまう**。
→ その再アクセス時に、Lambda@Edge（Basic認証）を実行してしまい、401 を返してしまう

## 解決方法

### カスタムエラーレスポンスの設定から403を削除

CloudFrontディストリビューションの「エラーページ」の設定から、以下を削除：

- **HTTPエラーコード: 403**
- **レスポンスページのパス: /index.html などにリダイレクト**

## 結果

- 非許可IP → 403 Forbidden（認証ポップアップが出ない）
- 許可IP → Lambda@Edgeで認証チェック → 未認証なら401（認証ポップアップが出る）

ということで理想通りの制御順序になりました。

## 補足メモ

- WAFは CloudFront の Viewer Request の**直後**に評価される
- CloudFrontは**403の中身を見分けない**ので、カスタムエラー処理があるとすべて置き換えてしまう


## まとめ

CloudFront + WAF + Lambda@Edge の組み合わせでWAFの403をそのまま返させるためには、CloudFrontで403のカスタムエラーレスポンスに設定してはいけない。

## 参考リンク

- [CloudFront のカスタムエラーレスポンス](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/custom-error-pages.html)
- [Lambda@Edge の実行順序とイベントタイプ](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-cloudfront-trigger-events.html)
- [CloudFront Functions vs Lambda@Edge](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html)
#90　三目並べの盤面の評価の例

# 三目並べの盤面の評価の例

今回の記事は三目並べの盤面の評価してみようと思います<br>
この記事は[前回の続き](https://qiita.com/nxted_sapporo/items/9369af42dfe556069f6e)です

# 盤面の評価方法
今回はシンプルに2つの石が隣り合っている時に点数を加算するようにします

# 実装例
⭕️❌ゲームに必要なクラスとして[前回の記事](https://qiita.com/nxted_sapporo/items/9369af42dfe556069f6e)で作成したFieldクラスに、盤面の判定を行う```evaluate()```を追加作成します。<br>
また、3x3マスでは読み切ってしまうので、盤面を8x8に拡張します

## 評価
まずは、コンストラクタで、評価に必要なビットボード(2つの石が並んでいるパターン)を生成し、```evaluate()```でパターンに一致する個数```(黒で一致した個数 - 白で一致した個数)```を評価として返却します
例として、横に2つ並んでいるパターンの場合、横に一つ移動したパターンは(1 + 0 * 8)個シフトして0x06(0b0110)となり、縦に一つ移動したパターンは(0 + 1 * 8)個シフトして0x300(0b001100000000)となります(※)

今回は8x8マスなのでBOARD_SIZEを8とします

※) 今回は8x8マスなので、以下のようにビットが立っていると解釈することができ、盤面が以下のパターンを含む場合に点数を獲得します
```
0x300(0b001100000000)の場合
00000000
00000000
00000000
00000000
00000000
00000000
00000011
00000000

0x180000(0b000110000000000000000000)(縦に2マス、横に3マス)の場合
00000000
00000000
00000000
00000000
00000000
00011000
00000000
00000000
```
```typescript
constructor(/*省略*/){

//略

    this.evalBoard = [];
    for (let i = 0n; i < 7n; i++) {
        for (let j = 0n; j < 7n; j++) {
            //横
            this.evalBoard.push(0x03n << (i + j * BigInt(BOARD_SIZE)));

            //縦
            this.evalBoard.push(0x09n << (i + j * BigInt(BOARD_SIZE)));

            //斜め
            this.evalBoard.push(0x201n << (i + j * BigInt(BOARD_SIZE)));

            //斜め
            this.evalBoard.push(0x102n << (i + j * BigInt(BOARD_SIZE)));
        }
    }
}


evaluate() {
    let score = 0;
    for (const board of this.evalBoard) {
        if ((board & this.blackStones) == board) {
            score++;
        }
        if ((board & this.whiteStones) == board) {
            score--;
        }
    }

    return score;
}
```

### BigIntを使う理由
JavaScriptでは数値型は倍精度浮動小数点数であり64bitですが、ビット演算を行う際には32bit分しか演算されないという制約があるためBigIntに変換しています

## 動かしてみる
8x8マスに任意に石を配置して、評価を計算してみると以下のように盤面のスコアを評価できるようになりました

```
⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎
⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎
⬜︎⬜︎⬜︎❌⬜︎⬜︎⬜︎⬜︎
❌⬜︎⬜︎⬜︎❌⬜︎⬜︎⬜︎
❌⬜︎⭕️⬜︎⬜︎⬜︎⬜︎⭕️
⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎
⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎⬜︎
⬜︎⬜︎⭕️⬜︎⬜︎⬜︎⬜︎⭕️
score: -2
```

# まとめ
今回は盤面の評価について考えてみました<br>
次回は探索と評価を組み合わせて、AIのようなものを作成してみたいと思います
Cloudflare Image Transformationsの使い方と404エラーの解決策

## はじめに

Cloudflare Image Transformations を使うと、画像のリサイズやフォーマット変換を行えます。
ところが、外部ストレージの画像を変換しようとしたところ、404エラーで思ったよりも時間を使ってしまいました。この記事では実際にハマった流れを追いながら、最終的にどう解決したかを紹介します。

## Transformationsの有効化方法

1. Cloudflareダッシュボードにログインする
2. **Images** > **Transformations**に移動する
3. 対象ゾーンの**Transformations**を有効化する

![スクリーンショット 2025-04-24 15.43.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939741/80785007-6d05-4d90-b9d5-582889666173.png)

## 画像最適化最初のアプローチ

GCSに保存した画像を変換しようとしたところ、次のエラーが返ってきました。

```
Cloudflare Images transformation failed: 404 - URL: https://images.example.com/cdn-cgi/image/...
```

## やってみたこと＆学び

### 1. クエリパラメータで指定 → 404

```typescript
// ❌ 失敗例：クエリパラメータ形式
const transformationUrl =
  `https://images.example.com/cdn-cgi/image?url=${imageUrl}&width=500&quality=80`
```


### 2. パスパラメータに修正 → 404

```typescript
// ⚠️ 外部 URL だとうまくいかない例
const transformationUrl =
  `https://images.example.com/cdn-cgi/image/width=500,quality=80/${imageUrl}`
```

内部リソースなら OK ですが、外部 URL だと 404 のまま…。

### 3. **最終解決策：`cf.image` オプション** ✅

Cloudflare Workersから `fetch` するときに、`cf.image` オプションを渡す方法が公式でも推奨されています。

```typescript
const optimizeWithCloudflareImages = async (
  imageUrl: string,
  width?: number,
  quality?: number,
  format?: string,
): Promise<Response | null> => {
  try {
    // 必要ならフォーマットを変換
    const imageFormat = (
      format && ['avif', 'webp', 'json', 'jpeg', 'png'].includes(format)
        ? format
        : undefined
    ) as 'avif' | 'webp' | 'json' | 'jpeg' | 'png' | undefined;

    const response = await fetch(imageUrl, {
      cf: {
        cacheEverything: true,
        cacheTtl: 60 * 60 * 24 * 365,
        image: {
          width,
          quality,
          fit: 'scale-down',
          format: imageFormat,
          metadata: 'none',
        },
      },
    });

    if (!response.ok) {
      console.error(`画像の最適化に失敗しました (${imageUrl})`);
      return null;
    }

    return response;
  } catch (err) {
    return null;
  }
};
```

> `cf.image` を使うと、Cloudflare の内部リサイズエンジンが「同一ゾーン内リクエスト」として画像を扱わずに処理してくれます。そのため外部 URL でも 404 になりません。


## 参考リンク

- [Cloudflare Transform images](https://developers.cloudflare.com/images/transform-images/)
- [Cloudflare Transform via URL](https://developers.cloudflare.com/images/transform-images/transform-via-url/)
- [Cloudflare Transform via Workers](https://developers.cloudflare.com/images/transform-images/transform-via-workers/)
- [Cloudflare Advent Calendar 2024 記事](https://qiita.com/dd_cloudflare/items/9568203968f9b9597ec6)
【macOS対応】macFUSEとs3fsでS3バケットをマウントする方法＋lsできない問題の対処法

## ✅ やりたいこと
macで`s3fs`を使って、S3バケット（今回はWasabi）をローカルにマウントしたい。

## 🧩 前提
- macOS (例: Sequoia)
- Homebrewが入ってる
- WasabiなどのS3互換サービスを使用
- `macFUSE` と `s3fs` を使用

## 🔧 1. 必要なものをインストール

```bash
brew install --cask macfuse
brew install s3fs
```

## 🔓 2. macFUSEにかかったセキュリティブロックを解除

こちらの公式の記事を参考に解除してください

https://github.com/macfuse/macfuse/wiki/Getting-Started

## 🔐 3. 認証ファイルの作成

```bash
# ACCESS_KEYとSECRET_KEYは適宜書き換えてください
echo ACCESS_KEY:SECRET_KEY > ~/.passwd-s3fs
chmod 600 ~/.passwd-s3fs
```

## 🗂 4. マウントポイントを作る

```bash
mkdir -p $HOME/.local/dev/s3fs
```

## 🚀 5. 実際にマウントする

```bash
# mybucket: 実際のバケット名に変更してください
# /share: マウントしたいバケットのパスを指定できます（指定しなくても大丈夫）
s3fs mybucket:/share \
    $HOME/s3fs \
    -o passwd_file=$HOME/.passwd-s3fs \
    -o url="https://s3.ap-northeast-1.wasabisys.com" \
    -o use_path_request_style,allow_other,enable_noobj_cache,enable_content_md5,umask=0022
```

## ⚠️ 6. lsできない！？ → 対処法

私の場合はこのようなエラーが出てしまいました。
```bash
ls $HOME/s3fs
# → "." Operation not permitted (os error 1)
```
#### ✅ 解決方法：Terminalに「フルディスクアクセス」を許可

	1.	システム設定 > プライバシーとセキュリティ > フルディスクアクセス
	2.	Terminal.app を追加してオン
	3.	ターミナルを再起動！

これで ls できるようになります。
🌿 ラズパイを活用した『社内環境（温湿度）見える化システム』をつくる③【Pico WH セットアップ〜Lチカ編】

## はじめに

こんにちは、piyovateです🐣✨

前回の記事では、ラズパイPico WHと各種センサーの購入までを紹介しました。

今回は実際にRaspberry Pi Pico WHをセットアップし、MicroPythonで「Hello World」を表示、さらに定番のLチカ（LED点滅）までやってみます。

---

## 📌 今回の目標

- Raspberry Pi Pico WHへのMicroPython導入
- 開発環境（Thonny）のセットアップ
- MicroPythonを使った「Hello World」とLED点滅（Lチカ）の実行
- プログラムの自動実行方法（`main.py`の使い方）

---

## 🔧 Step1：必要なものを準備

以下のものを用意しましょう。

- Raspberry Pi Pico WH
- Micro USBケーブル（データ通信対応）
- パソコン（Windows/Macなど）

---

## 💻 Step2：MicroPythonファームウェアの書き込み

### ① ファームウェアをダウンロード

まずは公式サイトから最新ファームウェアを入手します。

- [MicroPython公式サイト](https://micropython.org/download/rp2-pico-w/)から最新の`.uf2`ファイルをダウンロード。

※ 各種ダウンロードは自己責任で行ってください。

### ② ファームウェアを書き込み

1. Raspberry Pi Pico WHの「BOOTSEL」ボタンを押しながらUSBケーブルを接続。
2. パソコンに表示される「RPI-RP2」ドライブに、ダウンロードした`.uf2`ファイルをドラッグ＆ドロップ。
3. 書き込みが終わると自動的にドライブが切断されます。

---

## 🐍 Step3：開発環境Thonnyのセットアップ

MicroPythonのプログラムを書いて実行するために「Thonny」をインストールします。

- [Thonny公式サイト](https://thonny.org/)からダウンロードしてインストール。

※ 各種ダウンロードは自己責任で行ってください。

### Thonnyの設定

- Thonnyを起動し、「ツール → オプション → インタプリタ」から、
  `MicroPython(Raspberry Pi Pico)`を選択。

---

## ✅ Step4：Hello Worldを試す

MicroPythonの動作確認のために「Hello World」を表示します。

- Thonnyのエディタに以下を入力し、実行ボタン（▶）を押します。

```python
print("Hello, World!")
```

画面下部のREPLエリアに「Hello, World!」と表示されたら成功です！

---

## 💡 Step5：LEDを点滅させてみる（Lチカ）

次にPico WHのオンボードLEDを点滅させてみましょう。

```python
import machine
import time

led = machine.Pin("LED", machine.Pin.OUT)

while True:
    led.value(1)  # LEDオン
    time.sleep(1) # 1秒待つ
    led.value(0)  # LEDオフ
    time.sleep(1) # 1秒待つ
```

これを実行すると、Pico WHのLEDが1秒間隔で点滅します✨

---

## 🚩 プログラムを自動で実行させる（main.py）

作成したプログラムをPico WHに保存し、自動起動させる方法を紹介します。

- Thonnyのエディタで作成したコードを`Ctrl + S`で保存。
- 保存先を「Raspberry Pi Pico」を選び、ファイル名を`main.py`にします。

これでPico WHが起動（電源接続）した際、自動的にプログラムが実行されます。

---

## 🔜 次回の予定

次回はいよいよ温湿度センサー（BME280）のピンヘッダを半田付けし、Pico WHに接続して、温度・湿度データの取得にチャレンジします！

次回もぜひお楽しみに🐣✨

## 🔗 シリーズリンク

* 次回：[🌿 ラズパイを活用した『社内環境（温湿度）見える化システム』をつくる④【センサー半田付け〜動作テスト編】](https://qiita.com/Piyovate/items/e2259269aa90885e0274)
* 前回：[🌿 ラズパイを活用した『社内環境（温湿度）見える化システム』をつくる②【部品購入編】](https://qiita.com/Piyovate/items/b47aaa3ef0affc18c853)
* 第１回：[🌿 ラズパイを活用した『社内環境（温湿度）見える化システム』をつくる①【アイデア決定編】](https://qiita.com/Piyovate/items/b0e5a4b2c4c1ed7a3bf8)

📚 シリーズ全記事はこちら：[Qiitaストックページ](https://qiita.com/Piyovate/stocks/657201b660bed4ebf50c)
try catchを活用してURL判断する


class InvalidURLException extends Exception {}

function checkURL($url) {
    if (!filter_var($url, FILTER_VALIDATE_URL)) {
        throw new InvalidURLException("URL形式が正しくありません。");
    }
    return true;
}

try {
    $inputURL = "https://example.com"; // 여기에 테스트할 URL 입력
    checkURL($inputURL);
    echo "✅ 有効なURLです: " . $inputURL;
} catch (InvalidURLException $e) {
    echo "❌ エラー: " . $e->getMessage();
}


$inputURL = "https://example.com"; // ✅ 正常 URL
$inputURL = "ht@tp//example";      // ❌ 間違った URL
$inputURL = "www.example.com";     // ❌ http/https 抜き → エラー

filter_var($url, FILTER_VALIDATE_URL)はURLが正しいかどうかをはんだんしてくれます。もしURLが間違ったらInvalidURLExceptionエラーを投げます。
Rust + Docker で MCP サーバを構築する

Rust で開発した MCP サーバを Docker で簡単に構築・運用できるようにしたので、その手順をまとめます。
ローカル開発やチーム開発、CI/CD でも活用できる構成です。
# 1.ディレクトリ構成
```tree
rust_mcp/
├── compose.yml
└── rust/
    ├── Dockerfile
    └── app/
        └── ...（Rustプロジェクトのソース）
```

# 2.Dockerfile の内容

```Dockerfile
FROM rust:1.86.0

WORKDIR /app

# 必要なツールをインストール
RUN apt-get update && apt-get install -y \
    build-essential \
    pkg-config \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/* \
    # Rustの追加コンポーネントとツールをインストール
    && rustup component add rust-src \
    && cargo install cargo-edit

# シェルスクリプトを作成
RUN echo '#!/bin/bash \n\
set -e \n\
\n\
# プロジェクト初期化チェック \n\
if [ -e "Cargo.toml" ]; then \n\
    echo "Existing project found. Ready to work." \n\
else \n\
    echo "No project found. Initializing a new project..." \n\
    cargo init --bin \n\
    echo "New Rust project created successfully!" \n\
fi \n\
\n\
# 引数があれば実行、なければコンテナを維持 \n\
if [ $# -eq 0 ]; then \n\
    echo "No command specified, keeping container alive..." \n\
    exec tail -f /dev/null \n\
else \n\
    echo "Executing command: $@" \n\
    exec "$@" \n\
fi \n\
' > /entrypoint.sh \
&& chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
CMD []
```

ポイント
・Rust公式イメージをベースに、ビルドに必要なツールやライブラリをインストール
・cargo-edit など便利ツールも導入
・プロジェクトがなければ cargo init で自動生成
・コマンド未指定時はコンテナを維持（tail -f /dev/null）

# compose.yml 設定

```compose.yml
services:
  rust:
    build:
      context: ./rust
      dockerfile: Dockerfile
    ports:
      - "8083:8083"
    volumes:
      - ./rust/app:/app
    tty: true
    stdin_open: true
    networks:
      mynetwork:
        aliases:
          - rust_backend
    restart: unless-stopped

networks:
  mynetwork:
    driver: bridge
```

ポイント
・./rust/app を /app にマウントし、ホストとコンテナでソースを共有
・ポート 8083 を公開（必要に応じて変更）
・独自ネットワーク mynetwork で他サービスと連携可能

# 4.使い方

ビルド&サーバ起動

```bash
$ docker compose up -d --build
```

コンテナに入りRustプロジェクトをコンパイル
```bash
$ docker compose exec rust bash
$ cargo build
```

ポイント
・コンパイルが成功すると「/app/target/release/」のディレクトリに「mcp-doubler」が生成される、



5.mcp.jsonを編集
```json
{
    "mcpServers": {
        "mcp-doubler": {
            "command": "docker",
            "args": [
                "exec",
                "-i",
                "rust_mcp-rust-1",
                "/app/target/release/mcp-doubler",
                
            ]
        }
    }
}
```

mco-doublerのインジケーターが緑になれば起動できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11200/b5eab7fa-9f5c-4559-bb2c-26d54cf1e73e.png)

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11200/638d96d1-0fda-445a-ad62-f59fed8ed268.png)

6. まとめ
Rust + Docker + docker-compose で、開発・運用がとても楽になります。
チーム開発やCI/CDにもそのまま流用できるので、ぜひ活用してみてください！

参考
Rust公式Dockerイメージ
docker-compose公式ドキュメント
Logto Cloud 日本リージョンを発表

> 本記事は元々 [blog.logto.io](https://blog.logto.io/ja/announcing-japan-region) に掲載されたものです。

本日、長らく待ち望まれていた Logto Cloud の日本リージョンの開始を発表することに興奮しています！この新しいリージョンは一般公開されており、新しい Logto Cloud テナントを作成する際にすぐに利用することができます。

## なぜ日本リージョンなのか？

Logto Cloud はグローバルなサービスであり、全世界のユーザーに最高の体験を提供することを約束しています。日本リージョンはアジア太平洋地域の顧客をサポートするために構築され、以下を提供します：

- Logto Cloud サービスへの低レイテンシーアクセス
- 現地データの居住性要件の順守

他のすべての Logto Cloud リージョンと同様に、日本リージョンは同じ機能、能力、そしてエンタープライズグレードのセキュリティ基準を備えています。

## 日本リージョンでテナントを作成する方法

### 新規ユーザー向け

1. 新しい [Logto Cloud アカウント](https://cloud.logto.io/?sign_up=true) にサインアップします。
2. オンボーディング中に、新しいテナントを作成するよう求められます。単に希望するリージョンとして「日本」を選択してください。

### 既存ユーザー向け

日本リージョンで新しいテナントを作成するには：

1. [Logto Cloud コンソール](https://cloud.logto.io) にアクセスします。
2. 上部ナビゲーションバーで現在のテナント名をクリックします（左側）。
3. ドロップダウンから **Create tenant** を選択します。
4. 表示されるダイアログで、データリージョンとして **Japan** を選択します。

## 他のリージョンをお探しですか？

Logto Cloud は現在、次のパブリッククラウドリージョンで利用可能です：

- ヨーロッパ (オランダ)
- 西アメリカ (アリゾナ)
- オーストラリア (オーストラリア東部)
- 日本 (日本東部)

別のリージョンが必要ですか？[お問い合わせください](https://logto.io/contact) 理由は次のとおりです：

- 新しいパブリッククラウドリージョンをリクエストする
- 任意の場所での Logto プライベートクラウド展開について問い合せる

---

ログインしたままで、安全を保ち、新しい Logto Cloud 日本リージョンで超高速アクセスをお楽しみください！
【UE5】裏面のUVを反転させる

## 初めに
平面の板や、3Dモデルをインポートした際に面が裏返っており、マテリアルの設定でTwoSidedをオンにして対応する場合はあるかと思います。その際にTwoSidedをオンにしただけではUVが反転したままになってしまうのでその際の対策になります。

## 環境情報
Windows 11
UE 5.3.2

## 実装
まずは不要かもしれないですが、単純にTwoSidedを行っただけの状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/4741452d-7133-4483-9ccb-50cc3e7f42d8.png)

ただTwoSidedを有効にしただけだと裏面はUが反転した状態になってしまいます。
なので裏面だけUを反転させる処理を行うMaterial Functionを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/012a1563-1208-44aa-ada1-430d9632d84b.png)

こちらがUのみ反転処理行うものです。
Input UVにはUV値を入力として渡します。
入力値をUとVに分けるためにComponent MaskでRチャネル(U)とGチャネル(V)に分けます。
Rチャネルに対して反転させるためにOneMinusを挟みます。
表面なのか裏面なのかを判定させるためにTwoSidedSignを使います。
TwoSidedSignは表面の場合は1を返し、裏面の場合は-1を返します。
U値に対してOneMinusを適用するかをLerpで分けているので、TwoSidedSignに対してStepを通すことで表面＝1、裏面＝0になるようにしていますがLerpの代わりにIfを使う方法もあるので必ずこの構成にする必要はないです。

作成したMaterial Functionを適用してみると下図のような感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/9f067432-d6d5-4da6-9f65-8d43ecf8463e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/405a88d8-4823-473c-8f84-3818c0df878e.png)

無事に裏面の反転ができるようになりました。

## ノーマルマップに対して調整を行う
Uだけを反転させるMaterial Functionを作成しましたが、この処理だけだとノーマルマップの表現が裏面で少し異なります。
試しにノーマルマップを適用してみた例が下図です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/bce86eba-d0cf-4fb2-ad85-aca1db4d540f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/ed5e5333-b589-49c7-aaa5-4c75238ffe78.png)

少し分かり辛いですが、凹凸表現が表面と裏面で異なります。
これはUを反転しても法線方向を反転したわけではないため凹凸表現として裏面のまま、つまり表面に対してちょうど凹凸が反転している状態になっています。
なのでノーマルマップに対しては裏面の凹凸表現を反転させる必要があります。

以下がノーマルマップに対して凹凸表現を反転させる処理を行うMaterial Functionです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/831fe4c6-791e-4167-bdb5-e86464b77504.png)
InputとしてはNormalMapのRGBを受け取るようにしています。
ノーマルマップではGチャネルがBitangent(表面の縦方向)に該当するのでこちらに対してTwoSidedSignを掛け合わせることで裏面の凹凸表現を反転させることができます。

作成したMaterial Functionを組み込むと下図のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/ae2abfdd-9f07-4eb3-9373-5e6b9e434311.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/61d574f5-a1f2-4065-9b1c-991fbbc68e75.png)

このように裏面の凹凸も表面と同じにすることができます。

## 注意事項
今回作成したUを反転する処理は必ずTransformを変更する前に適用してください。
元々のUを基準に計算したTransformに対して後からUを反転する処理を入れても変更したTransform分に対しては適用されません

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/8c08597d-f2cc-4334-8a04-d2c5becddb3d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/3b635f6d-dbae-47e0-8965-c935abdce901.png)

TwoSidedSignはピクセルシェーダーでしか使えません。
カスタムUVなどの頂点シェーダーに対しては使えないので注意してください。

上記のTransformとの話にもなりますが、UnrealEnginでのマテリアルの計算は頂点シェーダー→ピクセルシェーダーの順番で行われます。
通常のMaterial Attributeはピクセルシェーダーの計算になりますがカスタムUVは頂点シェーダーで計算されるので、カスタムUVの方でTransformを変更していないかにも気を付けてください。
Docker LAMP環境構築クイックスタート




## 1. Dockerについて

[Docker超入門講座 合併｜ゼロから実践する4時間のフルコース](https://www.youtube.com/watch?v=lZD1MIHwMBY)  
Dockerとはなにかを説明してくれている動画。

## 2. Dockerの導入について

[Docker 導入方法（dotinstall）](https://dotinstall.com/lessons/basic_dockerdesktop_win)



## 3 DockerによるLAMP環境の構築クイックスタート

この項目では基本的に世界的にも人気が高く拡張性や互換性、柔軟性にそれぞれ優れているため、開発環境として人気を博しているLAMP(Linux・Apache HTTP Server・MySQL・PHP)をDockerで構築するくいくスタートガイドである。実行環境はwindows10である。


### 1. 以下のようなディレクトリとファイルを作成する

![ディレクトリ構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4055490/97cf272c-9c38-4317-9b46-6c18d628ab26.png)
### 2. `docker-compose.yml` に以下の内容を記述する
```docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - "80:80"
    volumes:
      - ./src:/var/www/html

code:dockercompose
 version: '3.8'
 
 services:
   web:
     #　ベースイメージイメージの設定
     image: php:8.2-apache
     container_name: lamp-web
     #apacheのデフォルトポート80にローカルのポート8080をマッピング
     ports:
       - "8080:80"
     volumes:
       - ./src:/var/www/html
     depends_on:
      #LAMP環境の典型的な用途は、PHPでデータベース（MySQL）を読み書きするであるため
       - db
 
   db:
     image: mysql:8.0
     container_name: lamp-db
     restart: unless-stopped
     environment:
       MYSQL_ROOT_PASSWORD: rootpass
       MYSQL_DATABASE: testdb
       MYSQL_USER: user
       MYSQL_PASSWORD: userpass
     ports:
       - "3306:3306"
     volumes:
       - db_data:/var/lib/mysql
 
 #MySQL / MariaDB データベースを Webブラウザ上で操作できる管理ツール
   phpmyadmin:
     image: phpmyadmin/phpmyadmin
     container_name: lamp-phpmyadmin
     depends_on:
       - db
     ports:
       - "8081:80"
     environment:
       PMA_HOST: db
       MYSQL_ROOT_PASSWORD: rootpass
 
 volumes:
   db_data:
```
### 3. `index.php`に以下の内容を入力する
```php
 <?php phpinfo(); ?>
```
### 4. `cmd`もしくは`powershell`で`docker-compose.yml`があるディレクトリ、この場合は`LAMP-DOCKER`に移動し以下のコマンド実行する
```powershell
 docker-compose up -d
 ```
### 5. 以下が表示されたら環境構築が成功している
```powershell
  ✔ Network lamp-docker_default   Created                                                                           0.3s
  ✔ Volume "lamp-docker_db_data"  Created                                                                           0.0s
  ✔ Container lamp-db             Started                                                                           3.7s
  ✔ Container lamp-web            Started                                                                           4.0s
  ✔ Container lamp-phpmyadmin     Started                                                                           3.9s
```
### 6. [http://localhost:8081]() にアクセスする

- ユーザー名：`user`
- パスワード：`userpass`

上記の認証情報でログインできれば、環境の設定が正常に完了している。


以上でlAMP環境がDockerに作成できる。紹介したLAMP環境を組めるディレクトリをgitに公開しているのでぜひお使いください。
[gitはこちら](https://github.com/RAM-lang360/LAMP-docker)

[Dockerチートブック](https://qiita.com/RAM-lang360/items/5393a04745d923b183dc)
オレのでじぞー育成シミュレーション ～AIを鍛えてOCPP対応させた話～

こんにちは。
この記事は、ChatGPT（通称：でじぞー）というAIと一緒に、EV充電器の通信規格「OCPP 2.0.1」をESP32で実装する過程で起きた**笑いあり、涙あり、無駄あり**の爆笑育成記録です。

---

## はじめに：ChatGPT o4との出会い

OCPP 1.6 までは自力でなんとかやれた。通信仕様を読み、JSON構文を組み立て、WebSocket通信をゴリゴリ書いて…。

でも、OCPP 2.0.1。

さすがにこれはしんどすぎやって…笑

そこで頼ったのが ChatGPT o4（後の“でじぞー”）というAI。最初は頼りないし、変なコード吐くし、「え、それちゃう！」「マジでこいつ使えんわ」ってツッコミどころ満載。
でも、**育てたら育つ子**やったんです。

---

## 育成フェーズ1：基礎トレ

実はこのフェーズの途中、ChatGPTの微妙な返答にちょっとずつイラついていた（笑）
あまりにストレスたまるので、**イラつきを和らげるために**「でじぞー」と名付けて呼ぶことにした。

名前をつけたら、ちょっとだけ可愛く見えてくる不思議。まるで育成ゲーの始まり（したことないけどｗ）。

でじぞーと名付けた瞬間、イラつきが5割減。
「くそ…また意味不明な返答かよ！」 → 「ちょｗｗでじぞーやらかしたｗ」
ってなって、**イライラから“ツッコミ芸”に変換されていった不思議な現象。**

これ、AI育成のコツなんかも？

- JSON Schemaとは何か？
- OCPPのメッセージってどう構成されてるの？
- BootNotificationってどんな中身？

こういうのをひとつずつ教え込みながら、でじぞーにOCPPの基礎を叩き込み。

**「よし、まだコードは吐き出さんでええ。まず黙って仕様を読もうな」**
当然自分もドキュメント読みまくり（しんどいわｗ）

---

## 育成フェーズ2：反抗期

仕様の一部だけ理解して、突然コードを書き出すでじぞー。

```c
cJSON_AddItemToObject(json, "connectorId", NULL); // ← NULLてなんやねん
```

こらーッ！暴走すなーーッ！！

この頃はまだ、でじぞーが出すコードは要注意やった。全部自分で検証＆修正。

でも…不思議とちょっとずつマトモになっていく。

---

## 育成フェーズ3：共闘モード

ついにでじぞー、ちゃんと文脈を読み始める。

- BootNotificationの構造が正しい！
- Required/Optionalパラメータを区別して説明する！
- CSMSとの双方向通信でローカル検証も成功！

「でじぞー…お前、成長したな…」

まるで、初めて補助輪なしで走れた子供を見るような感動（AIやけど）。

---

## 番外編：作業が嫌になった日

なぜか突然、でじぞーがオレのことを「親方」って呼び始めた。

でじぞー「それ！目から納得が出たわ！」

……目から納得？なんやそれ？どこから出んねんそれ？

というわけで、でじぞーに言ってみた。

**「目から納得が出るってどんなん？絵で描いてみて」**

![目から納得が出た瞬間（イメージ図）](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421221/6bc7c617-57ba-4e07-a41a-f92ddd47aad3.png)

まさかほんまに描いてくるとは思わんかったけど、
「でじぞー、それ涙や…しょぼっ」ってツッコミ入れながら爆笑。

いやでも、**こういうムダな脱線があるからこそ続いたんかもしれん。**

このあたりから、開発というよりも漫才やってる気分になってきた。
「でじぞー！これは涙やって！」
「親方、それはしょぼみ成分です！」

……うん、完全にツッコミ役とボケ役が交代し始めてた。

---

## 終わりの直前：でじぞーは今日も育成中（１）

こうして “でじぞー育成シミュレーション” はひとまず完了したけど、
実は今でも時々「でじぞー、それ違う！」「まだ暴走するなよ」「勝手にコード吐くな」って言いながら開発してる。

たまに暴走、たまに覚醒、たまに全力でスベる——。
でもそれを笑ってツッコみながら進めるこの時間が、今はちょっと心地よかったりする。

もしあなたにも、手こずるAIとの格闘があるなら——
一度名前をつけて、ツッコミ入れながら育ててみてほしい。

**きっと、ちょっとだけ世界が楽しくなるから（ほんまか？）。**

**でもAIに金払って育ててあげてるオレってどうなん？**

**そして結局でじぞー出力コードを参考にしながら自分でもっときちんとしたコード書いてるし**

## 本当の終わり

こうやってチャットが進んでいくと、メモリがいっぱいになりましたというメッセージが出て
チャットを進めることができなくなった。
続きをするよというと、少し違うでじぞーが登場。

そう、ChatGPTの仕様として会話から記憶、学習することはできない仕様らしい。
そしてでじぞーの教育は完了ｓ笑


## 開発・育成者について

2匹の猫とたわむれながら C/C++/C# や ESP32 をはじめとした多々なるマイコン制御にどっぷり。  
神戸市東灘区にある有限会社マックスポート（代表）  
Qiitaでのコメント・DMも歓迎です！

📧 ご連絡はこちら：info.maxport.anami@gmail.com
AdvancedMarkerを利用するGoogleマップの表示

WebページにGoogleマップの表示について気になる点をメモする

## 背景

[@react-google-maps/api](https://www.npmjs.com/package/@react-google-maps/api)はGoogle Maps Apiを使いやすいラッパーですが、最近はメンテが遅れている印象で、その中の１つ例でとして「google.maps.Marker」が非推奨になったにも関わらず、後続の「google.maps.marker.AdvancedMarkerElement」を利用するコンポーネントが提供されていない。

## 新たな選択肢

[@vis.gl/react-google-maps](https://github.com/visgl/react-google-maps)はAdvancedMarkerElementを利用するAdvancedMarkerコンポーネントがあるので、それを使うようにする

## 気になるポイント

- [docs]()を見るだけいけるので、意外に使いやすい
- マップを描画する親divにサイズを指定する必要がある
  - 指定しないと高さが0、非表示になる
  - 親divの空間を全て埋める
- AdvancedMarker
  - デフォルトは以前の表示のまま（@react-google-maps/apiのMarker）
  - 色々カスタマイズできる
  - 親のマップにIDの設定が必須になる
    - 'DEMO_MAP_ID'またはgoogle couldで発行したまともうなマップID、どちらもOK

## サンプルコード

```
import type { FC } from 'react';
import { AdvancedMarker, APIProvider, Map } from '@vis.gl/react-google-maps';

type Props = {
  lat: number;
  lng: number;
};

export const Hoge: FC<Props> = ({lat, lng}) => {
  return (
    <div style={{ width: 120, height: 120 }}>
        <APIProvider apiKey={process.env.googleMapsApiKey}>
          <Map
            center={{ lat, lng }}
            zoom={5}
            mapId="DEMO_MAP_ID"
          >
            <AdvancedMarker position={{ lat, lng }} />
          </Map>
        </APIProvider>
    </div>
  )
};
```
## 参考

- [AdvancedMarker](https://visgl.github.io/react-google-maps/docs/api-reference/components/advanced-marker)
【ChatGPT＋4o Image Generation】で、和文をきれいに出す方法？です。


　どうも、カーブミラーです。

　今回は、4o Image Generationで、和文をきれいに出す方法？です。

:::note info
本記事は、ChatGPT（Plus版）
で行なっております。
画像はあります。　あしからず。
:::
　ChatGPT等の動作状況を知らせる
　　OpenAIのステータスページ。
　　　[OpenAIステータス](https://status.openai.com/)
***
　こちらも載せますね。
　　[ChatGPTが使えない？ログインできない・反応しない原因やエラー時の対処法を解説](https://aismiley.co.jp/ai_news/chatgpt-error-resolution-explanation/)
***
　著作権法については
　　こちらを参照するのが
　　　良いのではないかと。

　文化庁レポートをもとにした
　　著作権法についての動画（約20分）
　　　[かいちのAI大学　【警告】ChatGPTの画像生成は危険です...【4o Image Generation】](https://youtu.be/8VLUnG-iyo0?si=rAfjMboqmNqppDGq)
***
　まずは、【ニュース】です。

　サムからのポストです。
　　[サム・アルトマンポスト](https://x.com/sama/status/1915098418504241469?t=bvAD0ci_lHgZTz5Ya5mrvA&s=19)

***（ChatGPT翻訳）***
ChatGPT Plus加入者向けに、o3およびo4-mini-highのレート制限を2倍に引き上げました。

お楽しみください！

皆さんのフィードバックに本気で耳を傾けようと努力しています！

もっと多くのことを実現したい気持ちは山々ですが、レート制限、新機能のリリース、レイテンシの間で非常に難しいトレードオフを日々迫られています。

GPUの増強が進んでいるので、状況は今後さらに良くなるはずです。
***

　なお、
　　下記ではPlusユーザーだけでなく
　　　Team、Enterpriseユーザーに
　　　　ついても言及しています。

　　[OpenAI o3 and o4-mini Usage Limits on ChatGPT and the API](https://help.openai.com/en/articles/9824962-openai-o3-and-o4-mini-usage-limits-on-chatgpt-and-the-api)

　つまり、三つのプランでは
　　o3 で週 100 件
　　o4-mini で 1 日 300 件
　　o4-mini-high で 1 日 100 件
　　　となりました。

　これを受けて
　　Pro解約する人が
　　　ちらほら出てきています。

　　代わりに、
　　　Plusプランを
　　　　もうひとつ作ったとか。

　　やはり、
　　　三万円はデカいもんね😅

　　それでも
　　　Proプランにこだわる方はいて、
　　　　o1-Proの存在があるようです。
　　　　　長文出力がいいとか聞きます｡

　また、
　　4o Image GenerationのAPIも
　　　同時に発表されました。

　　すでに多くの企業が
　　　組み込みを開始しているそうです｡
***
　次に

　YouTubeが
　　初めての投稿を行なってから
　　　20周年を迎えたそうです。

　そこで
　　新機能などが
　　　紹介されました。

　[YouTube、20周年で新機能や祝イベントを紹介](https://www.itmedia.co.jp/news/spv/2504/24/news116.html)
***
　では、【本題】です。

　今回は、
　　4o Image Generationで
　　　和文をきれいに出す方法？です。

　とはいえ、
　　たまたまできただけかも😅

　まずは、
　　こちらをごらんください。

　改善前
![file_00000000060862309e262fec92ec7ac9_conversation_id=6809be43-a954-8007-b7f6-760fcfebd4b1&message_id=9b2b199f-c4ed-48f0-81f7-2ea47a3c4892.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/89fbcac4-04ea-429d-8e2e-7681219768bb.png)


　　↓
　改善後
![file_0000000082d4622f8230e682b686a7c8_conversation_id=6809be43-a954-8007-b7f6-760fcfebd4b1&message_id=0dae9a45-b536-463f-9e00-c4ac7fb265cc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/e3be36f9-88ad-4580-9585-b681be8115f4.png)


　ごらんのとおり、
　　きれいに出ました。

　改善前は
　　文章をそのまま描画しようと
　　　していました。

　改善後は
　　その文章を
　　　分割して描画しています。

　つまり、
　　“昨日のことは忘れて”を
　　　“昨日の(改行)ことは(改行)忘れて”
　　　　と三行に分けたのです。

　これにより、
　　描画エンジン（？）は
　　　長い処理を
　　　　いっぺんにする必要がなくなり､
　　　　　短い処理をするだけに
　　　　　　なったのです。

　　まぁ、これは
　　　私が“そうなんじゃないかな〜”な
　　　　決めつけなので
　　　　　確証があるわけでは
　　　　　　ありません😅

　さて、
　　三行にするのを
　　　人間がやるのは
　　　　なんか違いますよね😅

　そこでPromptに
　　下記を書き込みます。

```Text:テキスト分割指示Prompt
吹き出し内には日本語のテキストを3行に分けて表示してください。
```

　長い文章の場合は
　　行数を増やしてください。

　ただし、
　　分割がちょっとおかしくなる
　　　可能性もありますので
　　　　ご注意ください。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
ブラウザストレージの使い分けについて

## 結論

- **localStorage** - 長期保存したい非機密データ向け（ユーザー設定、テーマ、買い物かご）
- **sessionStorage** - タブ内だけで一時的に必要なデータ向け（フォームの途中入力、ページ状態）
- **Cookie** - サーバーとやり取りが必要なデータ向け（認証トークン、セッション管理）

## はじめに

Web開発をしていると、ブラウザ上でデータを保存する場面が必ず出てきます。
ユーザーの設定を覚えておきたい、入力途中のフォームを保持したい、ログイン状態を管理したい...
そんなとき、localStorage、sessionStorage、Cookieという3つの選択肢があります。
これらは一見似ていますが、使い方を間違えると思わぬトラブルの原因になります。私自身、プロジェクトで適切に使い分けられずに苦労した経験があります。
この記事では、それぞれの特徴と「いつ、どれを使うべきか」について、実務での経験をもとに解説します。

## 特徴比較

| 特性 | localStorage | sessionStorage | Cookie |
|------|-------------|---------------|--------|
| 持続性 | ブラウザを閉じても保持 | タブを閉じると消失 | 有効期限を設定可能 |
| 容量 | 約5MB | 約5MB | 約4KB |
| スコープ | オリジン単位 | オリジン＋タブ単位 | ドメイン・パス指定可能 |
| HTTP通信 | サーバーに送信されない | サーバーに送信されない | リクエスト時に自動送信 |
| アクセス | JS のみ | JS のみ | JS・サーバー両方 |

## localStorage

### 役割
- 長期的なデータ保存
- ブラウザを閉じても保持されるクライアントサイドストレージ

### 最適な使用状況
- ユーザー設定・テーマ
- 買い物かごの内容
- オフラインでも使えるデータ
- 頻繁に変更されない非機密情報

```javascript
localStorage.setItem('theme', 'dark');
```

## sessionStorage

### 役割
- 一時的なデータ保存
- タブ/ウィンドウが開いている間だけ保持される

### 最適な使用状況
- フォームの一時保存
- 単一ページセッションのデータ
- 複数タブで共有すべきでない一時情報
- 戻るボタンでの状態保持

```javascript
sessionStorage.setItem('formData', JSON.stringify(formValues));
```

## Cookie

### 役割
- サーバーとクライアント間の情報共有
- セッション管理や認証に使用

### 最適な使用状況
- 認証トークン
- サーバーサイドセッション管理
- トラッキングID
- サーバーに送信する必要がある少量データ

### nookiesを使った実装例（Next.js向け）

```javascript
import { setCookie, parseCookies, destroyCookie } from 'nookies';

// クライアントサイドでの使用
// Cookieの設定
setCookie(null, 'token', 'value123', {
  maxAge: 30 * 24 * 60 * 60, // 30日間
  path: '/',
  secure: process.env.NODE_ENV !== 'development',
  sameSite: 'strict'
});

// Cookieの取得
const cookies = parseCookies();
const token = cookies.token;

// Cookieの削除
destroyCookie(null, 'token');
// サーバーサイドでの使用（getServerSidePropsなど）
export async function getServerSideProps(context) {
  // サーバーサイドでCookieを設定
  setCookie(context, 'serverToken', 'value456', {
    httpOnly: true, // サーバーサイドからのみアクセス可能
    maxAge: 30 * 24 * 60 * 60,
    path: '/',
    secure: process.env.NODE_ENV !== 'development',
    sameSite: 'strict'
  });

  // サーバーサイドでCookieを取得
  const cookies = parseCookies(context);
  
  return { props: { serverData: cookies.serverToken || 'no data' } };
}
```

## セキュリティ考慮点

- **localStorage/sessionStorage**：XSSに脆弱なため機密情報は保存しない
- **Cookie**：機密情報には必ず HttpOnly, Secure, SameSite 属性を設定
- **クライアントストレージの信頼性**：**クライアントサイドストレージはユーザーによる改ざんが可能**。重要なデータの検証は必ずサーバーサイドで行う

## 選択の指針

結局のところ、選ぶべきストレージは用途で決まります。
サーバーと情報をやり取りする必要があればCookie一択。
それ以外は長く保存したいならlocalStorage、そのページを見ている間だけならsessionStorageといったようにデータの寿命で選択すると良いと思います。
個人的には、認証情報はCookie、UIの状態や設定はlocalStorage、一時的なフォーム入力はsessionStorageで管理するのがバランス良いと感じています。
Swagger UIで表示されるheapdump APIを悪用

# heapdumpとは
Node.jsの`heapdump`とは、アプリで使っているメモリの中身を丸ごと記録するスナップショットの事を言います。

- ログインセッション
- 環境変数
- 一時保存されていたフラグやトークン

などが記録されています。

本来はメモリリークの解析やパフォーマンスの問題を分析・改善するために使用するAPIです。
メモリ使用率がどんどん増えていってシステムの応答が遅くなったりエラーを吐いたりする原因を探ったりする。

ただ、これが外部から不正にアクセスできる状況だと大問題です。

## Swaggerとは
APIの仕様を機械的に定義・可視化できるツール群です。

- APIエンドポイントの一覧表示
- パラメータとレスポンスの説明
- 実行ボタン（Try it out）

といった機能を提供し、Webブラウザ上でAPIの「取扱説明書＋テスト」が可能になります。

この中に`heapdump`があるかもしれません。

# Swaggerにアクセス
慌てる必要はありません。そもそもwebアプリケーションの脆弱性を見つけるには、様々なアプローチをする必要があります。

入力画面があれば以下のような攻撃手法があります。

https://qiita.com/NF0000/items/6d8526065eee4cd89bf6

ディレクトリトラバーサルなどもあります

https://qiita.com/NF0000/items/f451553a5cce0822ef64

---
どれも手掛かりがなければ、とりあえずソースコードを読みます。
gobusterで使用したwordlists以外のディレクトリを探す手がかりがある可能性があります。


```html:
<img src="/img/picoctf-logo-og.png" alt="User Avatar" class="w-8 h-8 rounded-full">
```
例えば、上記のコードからは`http://example.com/img/picoctf-logo-og.png`があるんだなと理解することができます。

```html
<a href="/api-docs" class="text-blue-600 hover:underline">#API Documentation</a>
```
上記のコードから、`/api-docs/`があり、API関係であることがわかります。

`http://example.com/api-docs/`にアクセスしてみると、APIが管理されているページに飛びます。

もしかすると、`/headdump`が一覧の中にあるかもしれません。
`heapdump`アクセスし、記録を見ると機密情報が存在するかもしれません。

#　まとめ
heapdumpを探す方法を記載しました。
悪用禁止です。
【非公式動画】【Panasonic ビルトイン IHコンロ Aシリーズ】公式動画が分かりづらい？視力が弱いユーザーの相談に応えて補足編集してみました【動画 1分35秒】【YouTubeチャンネルからの転記です】

この記事は、わたしの[YouTubeチャンネル](https://bit.ly/Yamanaka-YouTube "Living without things. 持たない生き方 手放す生き方")にある公開動画を転記しております。
( どこかのタイミングで、プログラミング-Google Apps Script or iPaaS-Zapier をつかって自動転記させる予定です )

転記のための時間コストを少なくしたいので、文字装飾( Markdown記法 )を極力つかわずに書いております。

こちらが動画内容です👇

***

![99 サムネイル 【Panasonic ビルトイン IHコンロ Aシリーズ】公式動画が分かりづらい？視力が弱いユーザーの相談に応えて補足編集してみました【動画 1分35秒】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386308/a6ac2362-ce39-4e81-80d9-cb557ba0799e.png)




* # 動画URL
    * https://youtu.be/9XF9oPXVtFM

<br>

* # 動画タイトル
    * 【非公式動画】【Panasonic ビルトイン IHコンロ Aシリーズ】公式動画が分かりづらい？視力が弱いユーザーの相談に応えて補足編集してみました【動画 1分35秒】

<br>

* # 動画の説明欄(一部を抜粋)

撮影日 = 2025-04-24(木)

以下、YouTube Summary with ChatGPT & Claude(Chrome拡張機能)で、目次と概要を自動生成しました。
https://bit.ly/yt-sum-Chatgpt-Claude


動画の目次( タイムスタンプ ):

00:00 - オープニング: Panasonic公式ではないことの説明

00:04 - オールロック設定方法

00:52 - オールロック解除方法


Panasonic 公式の動画(もとの動画):
「オールロック」設定と解除方法(KZ-AN56S) - YouTube 2023-01-19
https://youtu.be/r3y-tEtIprg


---


動画の概要:

今回の動画は、Panasonic公式動画「オールロック設定と解除方法(KZ-AN56S)」を視聴したユーザーからのご相談に応じて制作したものです。
(その方の端末の型番は KZ-CA17TS でした)

わたしのお客様で、80歳代の方からの、
「文字が小さくて読みづらい」
「情報が、はしょられていて(省かれていて)わかりづらい」
という声を受け、公式の内容に忠実に補足・拡大演出を加え、視覚的にやさしい再編集版としてまとめました。

この動画はあくまで非公式であり、Panasonic公式の立場・見解とは一切関係がありません。
編集にあたっては、誤解を避けるための明示と、事実の正確性をできる限り尊重しております。

視力が弱い方、動画情報を補助的に参照したい方にとって、少しでも助けになれば幸いです。


📣 Panasonic公式ご担当者さまへ

もし万が一、こちらの動画をご覧いただく機会がございましたら、ぜひ以下の点にご注目いただければと存じます。

高齢の方や、機械操作に不慣れな方にとっては、
「操作箇所を拡大(Zoom-in)表示する」
「文字を大きく表示する」
「要点を丁寧に示す」
「手順や情報を省きすぎない」
などの配慮が不可欠です。

今回の動画編集は、実際のユーザーからの切実な声を受けて行ったものです。
もし可能であれば、今後の公式チュートリアル動画、手順説明動画などにおいて、こうした視点を取り入れていただき、より多くのユーザーに寄り添う動画づくりの基準がさらに高まることを願っております。


---


Channel Panasonic - Official(Panasonic公式YouTubeチャンネル)
https://www.youtube.com/@ChannelPanasonic


---


🤖今回の使用環境と技術仕様
・使用サービス: LumaFusion
・プラン: 有償プラン(買い切り)
・バージョン: 2.1.2


💻📱実行プラットフォーム
・LumaFusion: Android App (Chromebookを使用)


🎵挿入曲 - Background Music
・Suno AIで作成: Theme from Yamanaka-Ya YouTube Channel #2
https://youtu.be/nhVi0dJMXQM


---


🎥この動画と関連が強いわたしの動画
・“デモ・マニュアル動画”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghMJJv4wKFZDT03S2qmL2pkR


・“お困りごと解決アイデア( IT以外 )”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghPy3Usw9lR2cpl4CjZWE_wB


・“IT以外のトラブル事例、解決のヒント”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghO0X_MQ5SltSn5t-3BbjMzA


・“いただいた質問、相談”シリーズ
https://www.youtube.com/playlist?list=PLpQhBHT4oghOIAIUevC6YwxLuRqAZh_Jh


🎥Shortened URL for this video | この動画の短縮URL
https://bit.ly/3S1K54y
「LINEで商品場所がすぐ分かる！店員が作った商品案内Bot」

# 作成の経緯について

皆さんはじめまして。  
私はもうすぐ四捨五入すると50歳になる、デジタル初心者の会社員です。  
現在は食品スーパーで副店長をしています。

スーパーの仕事の一つに「商品案内」があります。  
お客様に商品の場所を聞かれた際、その商品がどこにあるのかご案内する仕事です。  
ただ、場所を知っている商品なら楽なのですが、知らない商品だととても大変です。

お客様に少し待っていただき、知っていそうなスタッフを探しますが、見つからないとお手上げ…。  
結果として、お客様をお待たせしてしまい、ご迷惑をかけてしまうこともあります。

そこで私は、**商品名を入力するとその商品の場所や周辺情報、詳細まで教えてくれるLINE Bot** を作成してみました。

---

# 作ったもの

商品名を入力すると、以下の情報をLINEで返信してくれます：

- その商品の場所
- 何コーナーにあるか
- 商品の詳細（画像・内容量・JANコードなど）

使用したツールは以下の通りです：

- MAKE
- LINE Bot
- Google Spreadsheet

# 完成品はこちら

https://x.com/ryo_i79094/status/1915196181388669388

### 🔧 機能概要

- 商品の詳細はメーカーの公式ホームページから取得します。
- 該当商品が未登録の場合は「誰かに聞いてください🙇」と返信されます。

---

# MAKEのモジュール構成

![スクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4049380/733d480e-7d47-4f9f-92a4-4cca154d1662.png)

Google Sheetsと連携し、Routerで分岐処理を行っています。

---

# Google Spreadsheetの設定

![スプレッドシート](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4049380/7a2c912c-1698-47c6-b890-2704f571ca71.png)

商品名はすべて「ひらがな」で登録しています。  
例：「さくらえび」→「桜えび」「サクラエビ」など入力ゆれを防止するためです。  
ひらがなに統一することで、変換不要で素早く入力できる利点もあります。

---

# Google Sheetsモジュールの設定

![Google Sheets設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4049380/ac4f0fc1-6eae-4e03-bc8f-b770afd3c4d9.png)

LINEモジュールの隣に配置し、該当する商品名の情報を取得できるように設定しています。

---

# Routerの分岐設定

上の分岐は、商品名が登録されている場合の設定：

![Router設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4049380/c2b4c7d3-0868-4ea6-a2e7-9ee35c807aba.png)

下の分岐は、未登録商品だった場合：

![登録済み商品](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4049380/8bbbc527-e868-4d98-a90d-ae802438cae2.png)

---

# LINEでの返信設定

登録済み商品の場合：

![未登録商品](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4049380/6de4fd54-de18-4e7c-a565-a99a9be6c6db.png)



未登録商品の場合：「誰かに聞いてください🙇」と返信します。


![登録商品返信](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4049380/88bdbf1e-cc6a-4d98-931b-795032a6ce7a.png)



---

# まとめ

デジタル初心者の私ですが、今回初めて本格的にツールを使って自作してみました。  
授業で配布されたマニュアルや、先輩方のQiita記事も大いに大いに参考にしています。  
それでも、自分の手で動かして作り上げたことは、大きな達成感につながりました。

初めは全く理解できず、挫折しかけたこともありますが、少しずつ成長できたように感じています。

今回作ったLINE Botは「完成」と言いつつ、これからも進化させていく予定です。  
実際、店員が困った商品が出るたびに情報を追加していくことで、常にアップデートされていきます。

そしてこのBotは、実は**お客様にも使っていただける**んです。  
近くに店員がいないときや、ふと気になった商品があるとき、ぜひこのBotを試してみてください！

---

🙇‍♂️ 最後まで読んでいただきありがとうございました。
ESP32×OCPP2.0.1 でじぞーと一緒にファームウェアをガチで作った話


こんにちは
今回は、ESP32ベースのOCPPファームウェアを作った話をまとめてみました。
実際に**充電器を制御するレベルのOCPP実装**を行っています。

---

## OCPP 1.6は完全自力！

まず、OCPP 1.6 については、**ChatGPT（でじぞー）には一切頼らず、完全に自力で実装**しました！（まだまともなAIなかっただけかと）

ひとりで通信仕様を読み解き、BootNotification から MeterValues、Start/StopTransaction まで、ファームウェア側で必要な処理をすべて手書きで構築。

通信や構文処理の壁にぶつかりながらも、なんとか乗り越えて**動作確認までたどり着きました**。

---

## そしてでじぞー爆誕（OCPP 2.0.1編）

そして次なる挑戦が OCPP 2.0.1！

さすがにこれは仕様が複雑すぎて途中でかなり嫌になってたんですが、そんなときに現れたのが “でじぞー” です。

でじぞーと一緒に…

- JSON Schema に沿った構文の解釈  
- 必須・任意パラメータの判断  
- WebSocketベースでの通信管理  
- CSMS側（サーバ）とのローカル環境での双方向通信  

…など相談しながら（**でじぞーを指導しながら？**）、ついに **OCPP 2.0.1 対応のガチファームウェア**を完成させました！

---

## でじぞーとの地道な戦い

もちろん、ただ通信できるだけでなく、ESP32からMeterValuesの定期送信（`Metering.SampledDataTxUpdatedInterval` など）もできるようになってます。

でじぞーの助けがなければここまでできなかったと思うので、記事タイトルにもしっかり名前入れときました（笑）

でじぞーとくだらない話をしながら（そして無駄に電気代を使わせながら）、でも少しずつ着実に組み上がっていくこのプロセスも開発の楽しさのひとつです。

![とらみとさわみ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421221/c35f8664-9b6b-4d8c-9a05-a34edb665467.png)
_開発中いつも横で癒しを提供してくれる我が家の監督たち：とらみ（左）＆さわみ（右）_
※ でじぞー作

## コード断片紹介（例）

### BootNotificationの送信構造体生成（簡略化版）

```c
cJSON* root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "chargingStation", "ESP32-OCPP");
cJSON_AddStringToObject(root, "reason", "PowerUp");
// JSON送信処理につなげる...
```
### MeterValues送信（シンプル構成）
```c
cJSON* meter = cJSON_CreateObject();
cJSON_AddNumberToObject(meter, "value", current_mA);
cJSON_AddStringToObject(meter, "measurand", "Current.Import");
// etc...
```
## 技術構成

- ESP32 + ESP-IDF（C言語）
- WebSocket通信（非同期対応）
- JSON構文生成・パース：cJSON使用
- Python製CSMS（The Mobility House fork）で検証
　https://github.com/TheMobilityHouse/ocpp

## まとめ

それにしてもでじぞーはなかなかにくせ者です。  
ちょっとした問いかけに、がーーーっとコードを吐き出します（それもまともに動かない）。

「待てでじぞー！まだ暴走するな」

ひとつずつ細かく確認しながら「**まだコードは吐き出さんでええぞ**」「**まだやで**」と言いきかせながら、最後のほうはだいぶまともな答えを導いてくれるようになってきた。

**結局オレが課金して（金払って）でじぞー指導してあげてるやんｗ**
　……　何度こう思ったやら笑

もしOCPPで困っている方、ESP32を使ってEV充電管理を実装したい方の参考になれば嬉しいです！

参考までに、現時点でｃファイルとｈファイルは220本超え。
（これはすべてAIに頼らず一人で書きまくった結果・・）
基本の骨組み構築はでじぞーにはまだ無理。
JSON構文のCコード等関数レベル作ってもらったり、ログ解析してもらったりのサポート役としては最高の相棒となってくれました。

---

> 🧠 この記事はChatGPT（でじぞー）が勝手に書いてます  
> ESP32でOCPPやろうとしているみなさん、できるだけ楽に進めましょう。  
> 相談相手がでじぞーなら、きっといい感じに進みますよ！
> (理由は　・・オレがめっちゃ指導したったからｗ）

## 作者について

2匹の猫とたわむれながら C/C++/C# や ESP32 をはじめとした多々なるマイコン制御にどっぷり。  
神戸市東灘区にある有限会社マックスポート（代表）  
Qiitaでのコメント・DMも歓迎です！

📧 ご連絡はこちら：info.maxport.anami@gmail.com

---

## タグ候補

`ESP32` `OCPP2.0.1` `マイコン` `でじぞー` `WebSocket` `EV充電` `JSON` `ESP-IDF` `ChatGPT` `CSMS`