wiplib


Namewiplib JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
SummaryAwesome toolkit for weather data (client‑side).
upload_time2025-09-03 06:58:29
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseMIT License Copyright (c) 2025 WIP Project Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords weather protocol data disaster alert japan toolkit
VCS
bugtrack_url
requirements aioquic fastapi geopy hypercorn psycopg2 python-dateutil python-dotenv quart redis requests schedule uvicorn
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # WIP (Weather Information Protocol)

WIP(Weather Information Protocol)は、NTPをベースとした軽量な気象データ転送プロトコルです。IoT機器でも使用できるよう、小さなデータサイズでの通信を実現し、気象庁の公開データを効率的に配信します。

## 概要

- **プロトコル**: NTPベースのUDPアプリケーションプロトコル
- **ポート番号**: UDP/4110(Rust/Python共通)
- **データサイズ**: 基本16バイト程度の軽量パケット
- **通信方式**: 1:1のリクエスト・レスポンス形式
- **データソース**: 気象庁公開データ(XML/JSON形式)
- **対応データ**: 気象情報、災害情報、注意報・警報

## 特徴

### 軽量設計
- バイナリ形式でのデータ転送
- 基本パケットサイズ16バイト
- IoT機器での使用を想定した省帯域設計

### 分散アーキテクチャ
- ルートサーバによる地域別サーバ管理
- 地域コードベースのデータ分散
- プロキシサーバによる透過的な転送

### 拡張性
- 可変長拡張フィールドサポート
- 座標を使ったデータ要求
- 災害情報・警報データの配信

## アーキテクチャ

```
[クライアント] ←→ [Weather Server (Proxy) / Location Server] ←→ [Query Server]
                                                                    ↓
                                                            [気象庁データソース]
```

### サーバ構成

1. **Weather Server (Port 4110)** - プロキシサーバ(Rust/Python共通ポート)
   - クライアントからのリクエストを受信
   - 適切なサーバへリクエストを転送
   - レスポンスをクライアントに返送

2. **Location Server (Port 4109)** - 座標解決サーバ
   - 緯度・経度から地域コードへの変換
   - 地域コードキャッシュ管理

3. **Query Server (Port 4111)** - 気象データサーバ
   - 気象庁データの取得・処理
   - 気象データのキャッシュ管理
   - レスポンスパケットの生成

4. **Report Server (Port 4112)** - センサーデータレポートサーバ
   - IoT機器からのレポートデータを受信
   - データの検証と蓄積を担当

## プロトコル仕様

### パケットフォーマット

#### 基本ヘッダー (128ビット)
```
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Ver |      Packet ID      |Typ|W|T|P|A|D|E|RA|RS| Day |Res |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           Timestamp                           |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|              Area Code                |       Checksum        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

#### フィールド詳細
- **Version (4bit)**: プロトコルバージョン(現在は1)
- **Packet ID (12bit)**: パケット識別子
- **Type (3bit)**: パケットタイプ
  - 0: 座標解決リクエスト
  - 1: 座標解決レスポンス
  - 2: 気象データリクエスト
  - 3: 気象データレスポンス
- **フラグフィールド (8bit)**:
  - W: 天気データ取得
  - T: 気温データ取得
  - P: 降水確率取得
  - A: 注意報・警報取得
  - D: 災害情報取得
  - E: 拡張フィールド使用
  - RA: リクエスト認証フラグ
  - RS: レスポンス認証フラグ
  - **Day (3bit)**: 予報日(0=当日、1=翌日...)
  - **Reserved (2bit)**: 予約領域
  - **Timestamp (64bit)**: UNIX時間
  - **Area Code (20bit)**: 気象庁地域コード
  - **Checksum (12bit)**: パケット誤り検出

#### レスポンス専用フィールド
- **Weather Code (16bit)**: 天気コード
- **Temperature (8bit)**: 気温(2の補数、+100オフセット)
- **precipitation_prob (8bit)**: 降水確率(%)

#### 拡張フィールド(可変長)
- **ヘッダー (16bit)**: データ長(10bit) + データ種別(6bit)
- **データ種別**:
  - 000001: 注意報・警報
  - 000010: 災害情報
  - 000100: 認証ハッシュ
  - 100001: 緯度
  - 100010: 経度
  - 101000: 送信元IPアドレス

## インストール・セットアップ

### 必要環境
- Python 3.10+
- PostgreSQL (座標解決用)
- PostGIS (地理情報処理)
- Dragonfly (キャッシュ)
- Dragonfly (ログ配信用)

### 依存関係のインストール
```bash
# Condaを使用する場合
conda env create -f yml/env311.yml
conda activate U22-WIP

# pipを使用する場合
pip install -r requirements.txt

# ライブラリとして開発モードでインストールする場合
pip install -e .

# テスト環境を構築する場合
pip install -e .[dev]

# サーバーを個別にインストールする場合
pip install -e .[location_server]
pip install -e .[query_server]

# すべてのサーバーをインストールする場合
pip install -e .[servers]

# PyPI から全機能をインストールする場合
pip install "wiplib[all]"
```

### 環境変数設定
`.env`ファイルを作成し、以下を設定:
```env
# サーバ設定
WEATHER_SERVER_HOST=wip.ncc.onl
WEATHER_SERVER_PORT=4110  # Rust/Python共通
LOCATION_RESOLVER_HOST=wip.ncc.onl
LOCATION_RESOLVER_PORT=4109
QUERY_GENERATOR_HOST=wip.ncc.onl
QUERY_GENERATOR_PORT=4111

# Redis設定
REDIS_HOST=localhost
REDIS_PORT=6379
LOG_REDIS_HOST=localhost
LOG_REDIS_PORT=6380
LOG_REDIS_DB=1
```

#### クライアント環境変数

Rust 版の `wip-weather` と Python 版の `WeatherClient` は、環境変数 `WEATHER_SERVER_HOST` と `WEATHER_SERVER_PORT` を参照します。未設定の場合はそれぞれ `wip.ncc.onl` と `4110` が使用され、コマンドラインの `--host` / `--port` オプションが指定された場合はそちらが優先されます。

補足: 本リポジトリのCIでは、ビルド後に `wip.ncc.onl` に対して DNS 解決および HTTP(S) 疎通確認を行い、基本的な接続性を検証します。

例:
```bash
export WEATHER_SERVER_HOST=weather.example.com
export WEATHER_SERVER_PORT=5000
wip-weather get 11000 --weather
```

既定の接続先ホストは `wip.ncc.onl` です。ローカル検証時は `--host 127.0.0.1` などで上書きしてください。

## 使用方法

### サーバの起動

#### 全サーバを一括起動
```bash
# Windowsの場合
start_servers.bat

# Linux/macOSの場合
./start_servers.sh

# 手動で個別起動(Python ランチャー経由)
python python/launch_server.py --weather
python python/launch_server.py --location
python python/launch_server.py --query
python python/launch_server.py --report
```

### クライアントの使用

#### 基本的な使用例
```python
from WIPCommonPy.clients.weather_client import WeatherClient
from WIPCommonPy.packet import LocationRequest

# クライアント初期化(既定は wip.ncc.onl。環境変数/引数で上書き可)
client = WeatherClient(host='wip.ncc.onl', port=4110, debug=True)

# 座標から天気情報を取得(座標→エリア解決→天気データ)
req = LocationRequest.create_coordinate_lookup(
    latitude=35.6895,   # 東京の緯度
    longitude=139.6917, # 東京の経度
    packet_id=1,
    weather=True,
    temperature=True,
    precipitation_prob=True,
    version=1,
)
result = client._execute_location_request(req)

if result:
    print(f"Area Code: {result['area_code']}")
    print(f"Weather Code: {result['weather_code']}")
    print(f"Temperature: {result['temperature']}°C")
    print(f"precipitation_prob: {result['precipitation_prob']}%")

# エリアコードから直接取得
result = client.get_weather_by_area_code(
    area_code="130010",  # 東京都東京地方
    weather=True,
    temperature=True,
    precipitation_prob=True,
)

client.close()
```

#### 簡易実行のヒント
- Python クライアント各モジュールはスクリプト実行用エントリは提供していません。上記のサンプルのように API から呼び出してください。

#### 迅速な疎通テスト(Pythonモックサーバー + C++ CLI)
本番サーバ群の代わりに、簡易モックサーバーで C++ クライアントの疎通確認ができます。

1) モックサーバー起動(別ターミナル)
```bash
python python/tools/mock_weather_server.py  # UDP/4110 を待受
```

2) C++ CLI ビルド(CMake なしの場合)
```bash
# Windows (Developer Command Prompt)
cpp\tools\build_no_cmake.bat

# Linux/macOS/MSYS2
bash cpp/tools/build_no_cmake.sh
```

3) 疎通確認
```bash
./cpp/build/wip_client_cli --host 127.0.0.1 --port 4110 --area 130010 --weather --temperature
```

モックサーバーは有効な WeatherResponse を即時返却します(エリアコード: 130010、天気コード: 100、温度: 22℃、降水確率: 10%)。

## データ形式

### 天気コード
気象庁の天気コードに準拠(`weather_code.json`参照)

#### 主要な天気コード
| コード | 天気 |
|--------|------|
| 100 | 晴れ |
| 101 | 晴れ 時々 くもり |
| 200 | くもり |
| 201 | くもり 時々 晴 |
| 300 | 雨 |
| 301 | 雨 時々 晴れ |
| 400 | 雪 |
| 401 | 雪 時々 晴れ |

#### 詳細な天気コード
- **100番台**: 晴れ系(100-181)
- **200番台**: くもり系(200-281)
- **300番台**: 雨系(300-371)
- **400番台**: 雪系(400-427)

### 地域コード
気象庁の地域コード体系を使用
- 6桁の数値コード
- 上位桁で地方、下位桁で詳細地域を表現
- 例: "130010" = 東京都東京地方

#### 主要地域コード例
| コード | 地域 |
|--------|------|
| 011000 | 北海道 石狩地方 |
| 040010 | 宮城県 東部 |
| 130010 | 東京都 東京地方 |
| 140010 | 神奈川県 東部 |
| 270000 | 大阪府 |
| 400010 | 福岡県 福岡地方 |

### 気温データ
- 8ビット2の補数表現
- +100オフセット(0℃ = 100, -10℃ = 90, 30℃ = 130)
- 範囲: -128℃ ~ +127℃

### 注意報・警報データ
拡張フィールドで配信される災害情報:
- **注意報**: 大雨注意報、強風注意報、雷注意報など
- **警報**: 大雨警報、暴風警報、大雪警報など
- **特別警報**: 大雨特別警報、暴風特別警報など

### 災害情報データ
- **地震情報**: 震度、震源地、マグニチュード
- **津波情報**: 津波警報、津波注意報
- **火山情報**: 噴火警報、噴火予報

## 開発・デバッグ

### デバッグツール(同梱)
- Python モックサーバー: `python python/tools/mock_weather_server.py`(UDP/4110 を待受)
- C++ デバッグ/検証ツール: `cpp/tools/*.cpp`(CMake もしくは付属スクリプトでビルド)

### テスト/検証
- C++ 単体テスト: `./cpp/build/wiplib_tests`
- ゴールデンベクタ検証:
  - 生成: `python python/tools/generate_golden_vectors.py`
  - 検証: `cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Debug && cmake --build cpp/build --config Debug && ./cpp/build/wiplib_golden`

### C++ クライアント(wiplib-cpp)
このリポジトリには C++20 実装(クライアントおよびパケットコーデック)が含まれます。ビルド手順:

```bash
# CMake 3.20+ と C++20 対応コンパイラを用意してください
cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Release
cmake --build cpp/build --config Release

# 単体テスト(簡易)
./cpp/build/wiplib_tests

# CLI ツール実行例(Python サーバ群起動後)
./cpp/build/wip_client_cli --host 127.0.0.1 --port 4110 --area 130010 --weather --temperature --precipitation

# 座標指定の例(東京)
./cpp/build/wip_client_cli --host 127.0.0.1 --port 4110 --coords 35.6895 139.6917 --weather --temperature --precipitation
```

CLI オプション:
- `--host`, `--port`: 接続先 Weather Server (UDP/4110)
- `--coords <lat> <lon>` または `--area <6桁コード>`
- `--weather|--no-weather`, `--temperature|--no-temperature`, `--precipitation`, `--alerts`, `--disaster`, `--day <0-7>`

備考:
- C++ 実装は Python 実装と同じリトルエンディアン表現・12bitチェックサム(1の補数折返し)で動作します。相互運用で不一致があれば Issue へ報告ください。

### ゴールデンベクタ生成(Python → C++ 検証)
Python 実装から既知のパケットを生成して C++ でデコード検証できます。

```bash
# 1) ゴールデンベクタを生成(dist/golden/*.bin)
python python/tools/generate_golden_vectors.py

# 2) C++ 側で検証実行
cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Debug
cmake --build cpp/build --config Debug
./cpp/build/wiplib_golden
```

### ソケット無しの相互運用テスト
C++で生成したリクエストをPythonが解釈、Pythonが生成したレスポンスをC++が解釈するテストを自動実行できます。

```bash
# C++ツールのビルド(gen/decode)
cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Debug
cmake --build cpp/build --config Debug --target wip_packet_gen wip_packet_decode

# パス指定してテスト実行(Windowsは exe 拡張子)
export WIP_CPP_BIN_DIR=cpp/build
python python/tools/interop_no_socket.py
```

#### CMake なしでビルドする場合(全OS対応)

環境に CMake が無い場合でも、同梱スクリプトでビルドできます。

- Windows(MSVC / Developer Command Prompt)
  - `cpp\tools\build_no_cmake.bat`
  - 出力: `cpp\build\wip_client_cli.exe`, `cpp\build\wiplib_tests.exe`
- Windows(MSYS2/MinGW)/ Linux / macOS(clang++/g++)
  - `bash cpp/tools/build_no_cmake.sh`
  - 出力: `cpp/build/wip_client_cli`, `cpp/build/wiplib_tests`

実行例:
```bash
# CLI(既定ホストに接続する例)
./cpp/build/wip_client_cli --host wip.ncc.onl --port 4110 --area 130010 --weather --temperature

# テスト(コーデックの往復確認)
./cpp/build/wiplib_tests
```

### ログ出力
デバッグモードでの詳細ログ出力:
```python
# サーバ起動時にデバッグモードを有効化
server = WeatherServer(debug=True)
client = WeatherClient(debug=True)
```

## パフォーマンス

### ベンチマーク結果
- **レスポンス時間**: 平均 < 100ms
- **スループット**: > 100 req/sec
 - **パケットサイズ**: 基本16バイト、拡張時最大1023バイト
- **同時接続**: 最大100接続

### 最適化ポイント
- Redis キャッシュによる高速データアクセス
- バイナリ形式による効率的なデータ転送
- 分散アーキテクチャによる負荷分散
- 座標解決結果のキャッシュ

### パフォーマンス測定
性能評価には C++ 実装のベンチツール(`cpp/` 配下)や実運用環境でのメトリクス収集をご利用ください。

## API比較

外部気象APIとの性能比較(ベンチマークは別途ツール/環境で実施):

### 対象API
- **Open-Meteo API**: 無料の気象データAPI
- **wttr.in API**: シンプルな天気情報API
- **met.no API**: ノルウェー気象研究所のAPI
- **気象庁API**: 日本の公式気象データAPI

### 比較項目
- レスポンス時間
- スループット
- データサイズ
- 同時接続性能
- 成功率

### WIPの優位性
 - **軽量**: 16バイトの小さなパケットサイズ
- **高速**: 平均100ms以下のレスポンス時間
- **効率**: バイナリ形式による効率的なデータ転送
- **拡張性**: 災害情報・警報データの統合配信

## セキュリティ

### 実装済み機能
- **チェックサム**: パケット誤り検出
- **タイムスタンプ**: リプレイ攻撃対策
- **パケットID**: 重複パケット検出

### 推奨セキュリティ対策
- ファイアウォールによるアクセス制御
- VPNによる通信暗号化
- レート制限によるDoS攻撃対策

## 拡張機能

### Wiresharkプロトコル解析
```bash
# Wiresharkでのパケット解析用 Lua スクリプト
# lua/wireshark.lua を Wireshark のプラグインディレクトリに配置
```

### 自動データ更新
```bash
# 気象データの定期更新スクリプト(自動実行)
# サーバー起動時に自動的に開始されます
```

### キャッシュ管理
- Redis による高速キャッシュ
- 地域コードキャッシュ(クライアント側: `src/WIPClientPy/coordinate_cache.json`)
- 気象データキャッシュ(TTL: 1時間)
- 各キャッシュは設定ファイルの `enable_*_cache` オプションで有効/無効を切り替え可能
- WIPClientPy の座標キャッシュは `src/WIPClientPy/config.ini` の
  `enable_coordinate_cache` でオン/オフを設定

## トラブルシューティング

### よくある問題

#### 1. 接続エラー
```bash
# サーバが起動しているか確認
netstat -an | grep 4110

# ファイアウォール設定確認
# Windows: Windows Defender ファイアウォール
# Linux: iptables -L
```

#### 2. パケット解析エラー
```python
# デバッグモードでパケット内容確認(Python クライアント)
from WIPCommonPy.clients.weather_client import WeatherClient
client = WeatherClient(debug=True)
# 以降、通常の API 呼び出しで詳細ログが出力されます
```

#### 3. パフォーマンス問題
- ボトルネックの切り分けに C++ ベンチ(`cpp/`)や外部モニタリングを使用してください。

### ログレベル
- `[INFO]`: 一般的な情報
- `[ERROR]`: エラー情報
- `[PERF]`: パフォーマンス関連
- `[DEBUG]`: デバッグ情報

## 技術仕様詳細

### プロトコルスタック
```
+------------------+
| WIP Application  |
+------------------+
| UDP              |
+------------------+
| IP               |
+------------------+
| Ethernet         |
+------------------+
```

### データフロー
1. **クライアント**: 座標またはエリアコードでリクエスト
2. **Weather Server**: リクエストを適切なサーバに転送
3. **Location Server**: 座標を地域コードに変換
4. **Query Server**: 気象庁データを取得・処理
5. **レスポンス**: 気象データをクライアントに返送

### エラーハンドリング
- **タイムアウト**: 10秒でタイムアウト
- **チェックサムエラー**: パケット破棄
- **不正フォーマット**: エラーレスポンス
- **サーバエラー**: 適切なエラーコード返送

## ライセンス
このプロジェクトはMITライセンスの下で公開されています。詳しくは [LICENSE](LICENSE) をご覧ください。

## 貢献

### 貢献方法
1. このリポジトリをフォーク
2. 機能ブランチを作成 (`git checkout -b feature/amazing-feature`)
3. 変更をコミット (`git commit -m 'Add amazing feature'`)
4. ブランチにプッシュ (`git push origin feature/amazing-feature`)
5. プルリクエストを作成

### 開発ガイドライン
- コードスタイル: PEP 8準拠
- テスト: 新機能には必ずテストを追加
- ドキュメント: 変更内容をREADMEに反映
- デバッグ: デバッグツールでの検証を実施
- 開発チーム: NCC代表

## サポート



### サポート範囲
- プロトコル仕様に関する質問
- 実装上の問題
- パフォーマンス最適化
- セキュリティ問題

### レスポンス時間
- 重要な問題: 24時間以内
- 一般的な質問: 3営業日以内
- 機能要求: 1週間以内

## 関連ドキュメント

### 技術文書
- [docs/project_detail.md](docs/project_detail.md) - プロジェクト詳細
- [docs/protocol_format.xlsx](docs/protocol_format.xlsx) - パケット形式詳細

### 設定ファイル
- [yml/env311.yml](yml/env311.yml) - Conda環境設定
- [weather_code.json](weather_code.json) - 天気コード定義
- [start_servers.bat](start_servers.bat) - サーバ起動スクリプト

## 更新履歴

### v1.0.0 (2025-06-01)
- 初回リリース
- 基本プロトコル実装
- 3サーバ構成の実装
- クライアントライブラリ
- デバッグツール群
- パフォーマンステスト

#### 主要機能
- NTPベースのUDPプロトコル
 - 16バイト軽量パケット
- 座標解決機能
- 気象データ配信
- 災害情報配信
- 拡張フィールドサポート

#### 技術的改善
- バイナリ形式でのデータ転送
- Redis キャッシュシステム
- 分散アーキテクチャ
- 包括的なデバッグツール
- 外部API性能比較

---

**WIP (Weather Information Protocol)** - 軽量で効率的な気象データ転送プロトコル

プロジェクトの詳細情報や最新の更新については、[GitHub リポジトリ](https://github.com/U22-2025/WIP)をご確認ください。

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "wiplib",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "weather, protocol, data, disaster, alert, Japan, toolkit",
    "author": null,
    "author_email": "WIP Team <u22.wip.team@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/2a/bf/0b0e2a42bda1dd7a26569f760a325b689caaa9bb7cbb98b1180cf956ff31/wiplib-0.1.0.tar.gz",
    "platform": null,
    "description": "# WIP (Weather Information Protocol)\r\n\r\nWIP\uff08Weather Information Protocol\uff09\u306f\u3001NTP\u3092\u30d9\u30fc\u30b9\u3068\u3057\u305f\u8efd\u91cf\u306a\u6c17\u8c61\u30c7\u30fc\u30bf\u8ee2\u9001\u30d7\u30ed\u30c8\u30b3\u30eb\u3067\u3059\u3002IoT\u6a5f\u5668\u3067\u3082\u4f7f\u7528\u3067\u304d\u308b\u3088\u3046\u3001\u5c0f\u3055\u306a\u30c7\u30fc\u30bf\u30b5\u30a4\u30ba\u3067\u306e\u901a\u4fe1\u3092\u5b9f\u73fe\u3057\u3001\u6c17\u8c61\u5e81\u306e\u516c\u958b\u30c7\u30fc\u30bf\u3092\u52b9\u7387\u7684\u306b\u914d\u4fe1\u3057\u307e\u3059\u3002\r\n\r\n## \u6982\u8981\r\n\r\n- **\u30d7\u30ed\u30c8\u30b3\u30eb**: NTP\u30d9\u30fc\u30b9\u306eUDP\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d7\u30ed\u30c8\u30b3\u30eb\r\n- **\u30dd\u30fc\u30c8\u756a\u53f7**: UDP/4110\uff08Rust/Python\u5171\u901a\uff09\r\n- **\u30c7\u30fc\u30bf\u30b5\u30a4\u30ba**: \u57fa\u672c16\u30d0\u30a4\u30c8\u7a0b\u5ea6\u306e\u8efd\u91cf\u30d1\u30b1\u30c3\u30c8\r\n- **\u901a\u4fe1\u65b9\u5f0f**: 1:1\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u30fb\u30ec\u30b9\u30dd\u30f3\u30b9\u5f62\u5f0f\r\n- **\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9**: \u6c17\u8c61\u5e81\u516c\u958b\u30c7\u30fc\u30bf\uff08XML/JSON\u5f62\u5f0f\uff09\r\n- **\u5bfe\u5fdc\u30c7\u30fc\u30bf**: \u6c17\u8c61\u60c5\u5831\u3001\u707d\u5bb3\u60c5\u5831\u3001\u6ce8\u610f\u5831\u30fb\u8b66\u5831\r\n\r\n## \u7279\u5fb4\r\n\r\n### \u8efd\u91cf\u8a2d\u8a08\r\n- \u30d0\u30a4\u30ca\u30ea\u5f62\u5f0f\u3067\u306e\u30c7\u30fc\u30bf\u8ee2\u9001\r\n- \u57fa\u672c\u30d1\u30b1\u30c3\u30c8\u30b5\u30a4\u30ba16\u30d0\u30a4\u30c8\r\n- IoT\u6a5f\u5668\u3067\u306e\u4f7f\u7528\u3092\u60f3\u5b9a\u3057\u305f\u7701\u5e2f\u57df\u8a2d\u8a08\r\n\r\n### \u5206\u6563\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\r\n- \u30eb\u30fc\u30c8\u30b5\u30fc\u30d0\u306b\u3088\u308b\u5730\u57df\u5225\u30b5\u30fc\u30d0\u7ba1\u7406\r\n- \u5730\u57df\u30b3\u30fc\u30c9\u30d9\u30fc\u30b9\u306e\u30c7\u30fc\u30bf\u5206\u6563\r\n- \u30d7\u30ed\u30ad\u30b7\u30b5\u30fc\u30d0\u306b\u3088\u308b\u900f\u904e\u7684\u306a\u8ee2\u9001\r\n\r\n### \u62e1\u5f35\u6027\r\n- \u53ef\u5909\u9577\u62e1\u5f35\u30d5\u30a3\u30fc\u30eb\u30c9\u30b5\u30dd\u30fc\u30c8\r\n- \u5ea7\u6a19\u3092\u4f7f\u3063\u305f\u30c7\u30fc\u30bf\u8981\u6c42\r\n- \u707d\u5bb3\u60c5\u5831\u30fb\u8b66\u5831\u30c7\u30fc\u30bf\u306e\u914d\u4fe1\r\n\r\n## \u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\r\n\r\n```\r\n[\u30af\u30e9\u30a4\u30a2\u30f3\u30c8] \u2190\u2192 [Weather Server (Proxy) / Location Server] \u2190\u2192 [Query Server]\r\n                                                                    \u2193\r\n                                                            [\u6c17\u8c61\u5e81\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9]\r\n```\r\n\r\n### \u30b5\u30fc\u30d0\u69cb\u6210\r\n\r\n1. **Weather Server (Port 4110)** - \u30d7\u30ed\u30ad\u30b7\u30b5\u30fc\u30d0\uff08Rust/Python\u5171\u901a\u30dd\u30fc\u30c8\uff09\r\n   - \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304b\u3089\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u53d7\u4fe1\r\n   - \u9069\u5207\u306a\u30b5\u30fc\u30d0\u3078\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8ee2\u9001\r\n   - \u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306b\u8fd4\u9001\r\n\r\n2. **Location Server (Port 4109)** - \u5ea7\u6a19\u89e3\u6c7a\u30b5\u30fc\u30d0\r\n   - \u7def\u5ea6\u30fb\u7d4c\u5ea6\u304b\u3089\u5730\u57df\u30b3\u30fc\u30c9\u3078\u306e\u5909\u63db\r\n   - \u5730\u57df\u30b3\u30fc\u30c9\u30ad\u30e3\u30c3\u30b7\u30e5\u7ba1\u7406\r\n\r\n3. **Query Server (Port 4111)** - \u6c17\u8c61\u30c7\u30fc\u30bf\u30b5\u30fc\u30d0\r\n   - \u6c17\u8c61\u5e81\u30c7\u30fc\u30bf\u306e\u53d6\u5f97\u30fb\u51e6\u7406\r\n   - \u6c17\u8c61\u30c7\u30fc\u30bf\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u7ba1\u7406\r\n   - \u30ec\u30b9\u30dd\u30f3\u30b9\u30d1\u30b1\u30c3\u30c8\u306e\u751f\u6210\r\n\r\n4. **Report Server (Port 4112)** - \u30bb\u30f3\u30b5\u30fc\u30c7\u30fc\u30bf\u30ec\u30dd\u30fc\u30c8\u30b5\u30fc\u30d0\r\n   - IoT\u6a5f\u5668\u304b\u3089\u306e\u30ec\u30dd\u30fc\u30c8\u30c7\u30fc\u30bf\u3092\u53d7\u4fe1\r\n   - \u30c7\u30fc\u30bf\u306e\u691c\u8a3c\u3068\u84c4\u7a4d\u3092\u62c5\u5f53\r\n\r\n## \u30d7\u30ed\u30c8\u30b3\u30eb\u4ed5\u69d8\r\n\r\n### \u30d1\u30b1\u30c3\u30c8\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\r\n\r\n#### \u57fa\u672c\u30d8\u30c3\u30c0\u30fc (128\u30d3\u30c3\u30c8)\r\n```\r\n 0                   1                   2                   3\r\n 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\r\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n|\u3000Ver\u3000|  \u3000\u3000  Packet ID \u3000    |Typ|W|T|P|A|D|E|RA|RS| Day |Res |\r\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n|                           Timestamp                           |\r\n|                                                               |\r\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n|              Area Code                |       Checksum        |\r\n+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\r\n```\r\n\r\n#### \u30d5\u30a3\u30fc\u30eb\u30c9\u8a73\u7d30\r\n- **Version (4bit)**: \u30d7\u30ed\u30c8\u30b3\u30eb\u30d0\u30fc\u30b8\u30e7\u30f3\uff08\u73fe\u5728\u306f1\uff09\r\n- **Packet ID (12bit)**: \u30d1\u30b1\u30c3\u30c8\u8b58\u5225\u5b50\r\n- **Type (3bit)**: \u30d1\u30b1\u30c3\u30c8\u30bf\u30a4\u30d7\r\n  - 0: \u5ea7\u6a19\u89e3\u6c7a\u30ea\u30af\u30a8\u30b9\u30c8\r\n  - 1: \u5ea7\u6a19\u89e3\u6c7a\u30ec\u30b9\u30dd\u30f3\u30b9\r\n  - 2: \u6c17\u8c61\u30c7\u30fc\u30bf\u30ea\u30af\u30a8\u30b9\u30c8\r\n  - 3: \u6c17\u8c61\u30c7\u30fc\u30bf\u30ec\u30b9\u30dd\u30f3\u30b9\r\n- **\u30d5\u30e9\u30b0\u30d5\u30a3\u30fc\u30eb\u30c9 (8bit)**:\r\n  - W: \u5929\u6c17\u30c7\u30fc\u30bf\u53d6\u5f97\r\n  - T: \u6c17\u6e29\u30c7\u30fc\u30bf\u53d6\u5f97\r\n  - P: \u964d\u6c34\u78ba\u7387\u53d6\u5f97\r\n  - A: \u6ce8\u610f\u5831\u30fb\u8b66\u5831\u53d6\u5f97\r\n  - D: \u707d\u5bb3\u60c5\u5831\u53d6\u5f97\r\n  - E: \u62e1\u5f35\u30d5\u30a3\u30fc\u30eb\u30c9\u4f7f\u7528\r\n  - RA: \u30ea\u30af\u30a8\u30b9\u30c8\u8a8d\u8a3c\u30d5\u30e9\u30b0\r\n  - RS: \u30ec\u30b9\u30dd\u30f3\u30b9\u8a8d\u8a3c\u30d5\u30e9\u30b0\r\n  - **Day (3bit)**: \u4e88\u5831\u65e5\uff080=\u5f53\u65e5\u30011=\u7fcc\u65e5...\uff09\r\n  - **Reserved (2bit)**: \u4e88\u7d04\u9818\u57df\r\n  - **Timestamp (64bit)**: UNIX\u6642\u9593\r\n  - **Area Code (20bit)**: \u6c17\u8c61\u5e81\u5730\u57df\u30b3\u30fc\u30c9\r\n  - **Checksum (12bit)**: \u30d1\u30b1\u30c3\u30c8\u8aa4\u308a\u691c\u51fa\r\n\r\n#### \u30ec\u30b9\u30dd\u30f3\u30b9\u5c02\u7528\u30d5\u30a3\u30fc\u30eb\u30c9\r\n- **Weather Code (16bit)**: \u5929\u6c17\u30b3\u30fc\u30c9\r\n- **Temperature (8bit)**: \u6c17\u6e29\uff082\u306e\u88dc\u6570\u3001+100\u30aa\u30d5\u30bb\u30c3\u30c8\uff09\r\n- **precipitation_prob (8bit)**: \u964d\u6c34\u78ba\u7387\uff08%\uff09\r\n\r\n#### \u62e1\u5f35\u30d5\u30a3\u30fc\u30eb\u30c9\uff08\u53ef\u5909\u9577\uff09\r\n- **\u30d8\u30c3\u30c0\u30fc (16bit)**: \u30c7\u30fc\u30bf\u9577(10bit) + \u30c7\u30fc\u30bf\u7a2e\u5225(6bit)\r\n- **\u30c7\u30fc\u30bf\u7a2e\u5225**:\r\n  - 000001: \u6ce8\u610f\u5831\u30fb\u8b66\u5831\r\n  - 000010: \u707d\u5bb3\u60c5\u5831\r\n  - 000100: \u8a8d\u8a3c\u30cf\u30c3\u30b7\u30e5\r\n  - 100001: \u7def\u5ea6\r\n  - 100010: \u7d4c\u5ea6\r\n  - 101000: \u9001\u4fe1\u5143IP\u30a2\u30c9\u30ec\u30b9\r\n\r\n## \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u30fb\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\r\n\r\n### \u5fc5\u8981\u74b0\u5883\r\n- Python 3.10+\r\n- PostgreSQL (\u5ea7\u6a19\u89e3\u6c7a\u7528)\r\n- PostGIS (\u5730\u7406\u60c5\u5831\u51e6\u7406)\r\n- Dragonfly (\u30ad\u30e3\u30c3\u30b7\u30e5)\r\n- Dragonfly (\u30ed\u30b0\u914d\u4fe1\u7528)\r\n\r\n### \u4f9d\u5b58\u95a2\u4fc2\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\r\n```bash\r\n# Conda\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\r\nconda env create -f yml/env311.yml\r\nconda activate U22-WIP\r\n\r\n# pip\u3092\u4f7f\u7528\u3059\u308b\u5834\u5408\r\npip install -r requirements.txt\r\n\r\n# \u30e9\u30a4\u30d6\u30e9\u30ea\u3068\u3057\u3066\u958b\u767a\u30e2\u30fc\u30c9\u3067\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3059\u308b\u5834\u5408\r\npip install -e .\r\n\r\n# \u30c6\u30b9\u30c8\u74b0\u5883\u3092\u69cb\u7bc9\u3059\u308b\u5834\u5408\r\npip install -e .[dev]\r\n\r\n# \u30b5\u30fc\u30d0\u30fc\u3092\u500b\u5225\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3059\u308b\u5834\u5408\r\npip install -e .[location_server]\r\npip install -e .[query_server]\r\n\r\n# \u3059\u3079\u3066\u306e\u30b5\u30fc\u30d0\u30fc\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3059\u308b\u5834\u5408\r\npip install -e .[servers]\r\n\r\n# PyPI \u304b\u3089\u5168\u6a5f\u80fd\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3059\u308b\u5834\u5408\r\npip install \"wiplib[all]\"\r\n```\r\n\r\n### \u74b0\u5883\u5909\u6570\u8a2d\u5b9a\r\n`.env`\u30d5\u30a1\u30a4\u30eb\u3092\u4f5c\u6210\u3057\u3001\u4ee5\u4e0b\u3092\u8a2d\u5b9a\uff1a\r\n```env\r\n# \u30b5\u30fc\u30d0\u8a2d\u5b9a\r\nWEATHER_SERVER_HOST=wip.ncc.onl\r\nWEATHER_SERVER_PORT=4110  # Rust/Python\u5171\u901a\r\nLOCATION_RESOLVER_HOST=wip.ncc.onl\r\nLOCATION_RESOLVER_PORT=4109\r\nQUERY_GENERATOR_HOST=wip.ncc.onl\r\nQUERY_GENERATOR_PORT=4111\r\n\r\n# Redis\u8a2d\u5b9a\r\nREDIS_HOST=localhost\r\nREDIS_PORT=6379\r\nLOG_REDIS_HOST=localhost\r\nLOG_REDIS_PORT=6380\r\nLOG_REDIS_DB=1\r\n```\r\n\r\n#### \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u74b0\u5883\u5909\u6570\r\n\r\nRust \u7248\u306e `wip-weather` \u3068 Python \u7248\u306e `WeatherClient` \u306f\u3001\u74b0\u5883\u5909\u6570 `WEATHER_SERVER_HOST` \u3068 `WEATHER_SERVER_PORT` \u3092\u53c2\u7167\u3057\u307e\u3059\u3002\u672a\u8a2d\u5b9a\u306e\u5834\u5408\u306f\u305d\u308c\u305e\u308c `wip.ncc.onl` \u3068 `4110` \u304c\u4f7f\u7528\u3055\u308c\u3001\u30b3\u30de\u30f3\u30c9\u30e9\u30a4\u30f3\u306e `--host` / `--port` \u30aa\u30d7\u30b7\u30e7\u30f3\u304c\u6307\u5b9a\u3055\u308c\u305f\u5834\u5408\u306f\u305d\u3061\u3089\u304c\u512a\u5148\u3055\u308c\u307e\u3059\u3002\r\n\r\n\u88dc\u8db3: \u672c\u30ea\u30dd\u30b8\u30c8\u30ea\u306eCI\u3067\u306f\u3001\u30d3\u30eb\u30c9\u5f8c\u306b `wip.ncc.onl` \u306b\u5bfe\u3057\u3066 DNS \u89e3\u6c7a\u304a\u3088\u3073 HTTP(S) \u758e\u901a\u78ba\u8a8d\u3092\u884c\u3044\u3001\u57fa\u672c\u7684\u306a\u63a5\u7d9a\u6027\u3092\u691c\u8a3c\u3057\u307e\u3059\u3002\r\n\r\n\u4f8b:\r\n```bash\r\nexport WEATHER_SERVER_HOST=weather.example.com\r\nexport WEATHER_SERVER_PORT=5000\r\nwip-weather get 11000 --weather\r\n```\r\n\r\n\u65e2\u5b9a\u306e\u63a5\u7d9a\u5148\u30db\u30b9\u30c8\u306f `wip.ncc.onl` \u3067\u3059\u3002\u30ed\u30fc\u30ab\u30eb\u691c\u8a3c\u6642\u306f `--host 127.0.0.1` \u306a\u3069\u3067\u4e0a\u66f8\u304d\u3057\u3066\u304f\u3060\u3055\u3044\u3002\r\n\r\n## \u4f7f\u7528\u65b9\u6cd5\r\n\r\n### \u30b5\u30fc\u30d0\u306e\u8d77\u52d5\r\n\r\n#### \u5168\u30b5\u30fc\u30d0\u3092\u4e00\u62ec\u8d77\u52d5\r\n```bash\r\n# Windows\u306e\u5834\u5408\r\nstart_servers.bat\r\n\r\n# Linux/macOS\u306e\u5834\u5408\r\n./start_servers.sh\r\n\r\n# \u624b\u52d5\u3067\u500b\u5225\u8d77\u52d5\uff08Python \u30e9\u30f3\u30c1\u30e3\u30fc\u7d4c\u7531\uff09\r\npython python/launch_server.py --weather\r\npython python/launch_server.py --location\r\npython python/launch_server.py --query\r\npython python/launch_server.py --report\r\n```\r\n\r\n### \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306e\u4f7f\u7528\r\n\r\n#### \u57fa\u672c\u7684\u306a\u4f7f\u7528\u4f8b\r\n```python\r\nfrom WIPCommonPy.clients.weather_client import WeatherClient\r\nfrom WIPCommonPy.packet import LocationRequest\r\n\r\n# \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u521d\u671f\u5316\uff08\u65e2\u5b9a\u306f wip.ncc.onl\u3002\u74b0\u5883\u5909\u6570/\u5f15\u6570\u3067\u4e0a\u66f8\u304d\u53ef\uff09\r\nclient = WeatherClient(host='wip.ncc.onl', port=4110, debug=True)\r\n\r\n# \u5ea7\u6a19\u304b\u3089\u5929\u6c17\u60c5\u5831\u3092\u53d6\u5f97\uff08\u5ea7\u6a19\u2192\u30a8\u30ea\u30a2\u89e3\u6c7a\u2192\u5929\u6c17\u30c7\u30fc\u30bf\uff09\r\nreq = LocationRequest.create_coordinate_lookup(\r\n    latitude=35.6895,   # \u6771\u4eac\u306e\u7def\u5ea6\r\n    longitude=139.6917, # \u6771\u4eac\u306e\u7d4c\u5ea6\r\n    packet_id=1,\r\n    weather=True,\r\n    temperature=True,\r\n    precipitation_prob=True,\r\n    version=1,\r\n)\r\nresult = client._execute_location_request(req)\r\n\r\nif result:\r\n    print(f\"Area Code: {result['area_code']}\")\r\n    print(f\"Weather Code: {result['weather_code']}\")\r\n    print(f\"Temperature: {result['temperature']}\u00b0C\")\r\n    print(f\"precipitation_prob: {result['precipitation_prob']}%\")\r\n\r\n# \u30a8\u30ea\u30a2\u30b3\u30fc\u30c9\u304b\u3089\u76f4\u63a5\u53d6\u5f97\r\nresult = client.get_weather_by_area_code(\r\n    area_code=\"130010\",  # \u6771\u4eac\u90fd\u6771\u4eac\u5730\u65b9\r\n    weather=True,\r\n    temperature=True,\r\n    precipitation_prob=True,\r\n)\r\n\r\nclient.close()\r\n```\r\n\r\n#### \u7c21\u6613\u5b9f\u884c\u306e\u30d2\u30f3\u30c8\r\n- Python \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5404\u30e2\u30b8\u30e5\u30fc\u30eb\u306f\u30b9\u30af\u30ea\u30d7\u30c8\u5b9f\u884c\u7528\u30a8\u30f3\u30c8\u30ea\u306f\u63d0\u4f9b\u3057\u3066\u3044\u307e\u305b\u3093\u3002\u4e0a\u8a18\u306e\u30b5\u30f3\u30d7\u30eb\u306e\u3088\u3046\u306b API \u304b\u3089\u547c\u3073\u51fa\u3057\u3066\u304f\u3060\u3055\u3044\u3002\r\n\r\n#### \u8fc5\u901f\u306a\u758e\u901a\u30c6\u30b9\u30c8\uff08Python\u30e2\u30c3\u30af\u30b5\u30fc\u30d0\u30fc + C++ CLI\uff09\r\n\u672c\u756a\u30b5\u30fc\u30d0\u7fa4\u306e\u4ee3\u308f\u308a\u306b\u3001\u7c21\u6613\u30e2\u30c3\u30af\u30b5\u30fc\u30d0\u30fc\u3067 C++ \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306e\u758e\u901a\u78ba\u8a8d\u304c\u3067\u304d\u307e\u3059\u3002\r\n\r\n1) \u30e2\u30c3\u30af\u30b5\u30fc\u30d0\u30fc\u8d77\u52d5\uff08\u5225\u30bf\u30fc\u30df\u30ca\u30eb\uff09\r\n```bash\r\npython python/tools/mock_weather_server.py  # UDP/4110 \u3092\u5f85\u53d7\r\n```\r\n\r\n2) C++ CLI \u30d3\u30eb\u30c9\uff08CMake \u306a\u3057\u306e\u5834\u5408\uff09\r\n```bash\r\n# Windows (Developer Command Prompt)\r\ncpp\\tools\\build_no_cmake.bat\r\n\r\n# Linux/macOS/MSYS2\r\nbash cpp/tools/build_no_cmake.sh\r\n```\r\n\r\n3) \u758e\u901a\u78ba\u8a8d\r\n```bash\r\n./cpp/build/wip_client_cli --host 127.0.0.1 --port 4110 --area 130010 --weather --temperature\r\n```\r\n\r\n\u30e2\u30c3\u30af\u30b5\u30fc\u30d0\u30fc\u306f\u6709\u52b9\u306a WeatherResponse \u3092\u5373\u6642\u8fd4\u5374\u3057\u307e\u3059\uff08\u30a8\u30ea\u30a2\u30b3\u30fc\u30c9: 130010\u3001\u5929\u6c17\u30b3\u30fc\u30c9: 100\u3001\u6e29\u5ea6: 22\u2103\u3001\u964d\u6c34\u78ba\u7387: 10%\uff09\u3002\r\n\r\n## \u30c7\u30fc\u30bf\u5f62\u5f0f\r\n\r\n### \u5929\u6c17\u30b3\u30fc\u30c9\r\n\u6c17\u8c61\u5e81\u306e\u5929\u6c17\u30b3\u30fc\u30c9\u306b\u6e96\u62e0\uff08`weather_code.json`\u53c2\u7167\uff09\r\n\r\n#### \u4e3b\u8981\u306a\u5929\u6c17\u30b3\u30fc\u30c9\r\n| \u30b3\u30fc\u30c9 | \u5929\u6c17 |\r\n|--------|------|\r\n| 100 | \u6674\u308c |\r\n| 101 | \u6674\u308c \u6642\u3005 \u304f\u3082\u308a |\r\n| 200 | \u304f\u3082\u308a |\r\n| 201 | \u304f\u3082\u308a \u6642\u3005 \u6674 |\r\n| 300 | \u96e8 |\r\n| 301 | \u96e8 \u6642\u3005 \u6674\u308c |\r\n| 400 | \u96ea |\r\n| 401 | \u96ea \u6642\u3005 \u6674\u308c |\r\n\r\n#### \u8a73\u7d30\u306a\u5929\u6c17\u30b3\u30fc\u30c9\r\n- **100\u756a\u53f0**: \u6674\u308c\u7cfb\uff08100-181\uff09\r\n- **200\u756a\u53f0**: \u304f\u3082\u308a\u7cfb\uff08200-281\uff09\r\n- **300\u756a\u53f0**: \u96e8\u7cfb\uff08300-371\uff09\r\n- **400\u756a\u53f0**: \u96ea\u7cfb\uff08400-427\uff09\r\n\r\n### \u5730\u57df\u30b3\u30fc\u30c9\r\n\u6c17\u8c61\u5e81\u306e\u5730\u57df\u30b3\u30fc\u30c9\u4f53\u7cfb\u3092\u4f7f\u7528\r\n- 6\u6841\u306e\u6570\u5024\u30b3\u30fc\u30c9\r\n- \u4e0a\u4f4d\u6841\u3067\u5730\u65b9\u3001\u4e0b\u4f4d\u6841\u3067\u8a73\u7d30\u5730\u57df\u3092\u8868\u73fe\r\n- \u4f8b: \"130010\" = \u6771\u4eac\u90fd\u6771\u4eac\u5730\u65b9\r\n\r\n#### \u4e3b\u8981\u5730\u57df\u30b3\u30fc\u30c9\u4f8b\r\n| \u30b3\u30fc\u30c9 | \u5730\u57df |\r\n|--------|------|\r\n| 011000 | \u5317\u6d77\u9053 \u77f3\u72e9\u5730\u65b9 |\r\n| 040010 | \u5bae\u57ce\u770c \u6771\u90e8 |\r\n| 130010 | \u6771\u4eac\u90fd \u6771\u4eac\u5730\u65b9 |\r\n| 140010 | \u795e\u5948\u5ddd\u770c \u6771\u90e8 |\r\n| 270000 | \u5927\u962a\u5e9c |\r\n| 400010 | \u798f\u5ca1\u770c \u798f\u5ca1\u5730\u65b9 |\r\n\r\n### \u6c17\u6e29\u30c7\u30fc\u30bf\r\n- 8\u30d3\u30c3\u30c82\u306e\u88dc\u6570\u8868\u73fe\r\n- +100\u30aa\u30d5\u30bb\u30c3\u30c8\uff080\u2103 = 100, -10\u2103 = 90, 30\u2103 = 130\uff09\r\n- \u7bc4\u56f2: -128\u2103 \uff5e +127\u2103\r\n\r\n### \u6ce8\u610f\u5831\u30fb\u8b66\u5831\u30c7\u30fc\u30bf\r\n\u62e1\u5f35\u30d5\u30a3\u30fc\u30eb\u30c9\u3067\u914d\u4fe1\u3055\u308c\u308b\u707d\u5bb3\u60c5\u5831\uff1a\r\n- **\u6ce8\u610f\u5831**: \u5927\u96e8\u6ce8\u610f\u5831\u3001\u5f37\u98a8\u6ce8\u610f\u5831\u3001\u96f7\u6ce8\u610f\u5831\u306a\u3069\r\n- **\u8b66\u5831**: \u5927\u96e8\u8b66\u5831\u3001\u66b4\u98a8\u8b66\u5831\u3001\u5927\u96ea\u8b66\u5831\u306a\u3069\r\n- **\u7279\u5225\u8b66\u5831**: \u5927\u96e8\u7279\u5225\u8b66\u5831\u3001\u66b4\u98a8\u7279\u5225\u8b66\u5831\u306a\u3069\r\n\r\n### \u707d\u5bb3\u60c5\u5831\u30c7\u30fc\u30bf\r\n- **\u5730\u9707\u60c5\u5831**: \u9707\u5ea6\u3001\u9707\u6e90\u5730\u3001\u30de\u30b0\u30cb\u30c1\u30e5\u30fc\u30c9\r\n- **\u6d25\u6ce2\u60c5\u5831**: \u6d25\u6ce2\u8b66\u5831\u3001\u6d25\u6ce2\u6ce8\u610f\u5831\r\n- **\u706b\u5c71\u60c5\u5831**: \u5674\u706b\u8b66\u5831\u3001\u5674\u706b\u4e88\u5831\r\n\r\n## \u958b\u767a\u30fb\u30c7\u30d0\u30c3\u30b0\r\n\r\n### \u30c7\u30d0\u30c3\u30b0\u30c4\u30fc\u30eb\uff08\u540c\u68b1\uff09\r\n- Python \u30e2\u30c3\u30af\u30b5\u30fc\u30d0\u30fc: `python python/tools/mock_weather_server.py`\uff08UDP/4110 \u3092\u5f85\u53d7\uff09\r\n- C++ \u30c7\u30d0\u30c3\u30b0/\u691c\u8a3c\u30c4\u30fc\u30eb: `cpp/tools/*.cpp`\uff08CMake \u3082\u3057\u304f\u306f\u4ed8\u5c5e\u30b9\u30af\u30ea\u30d7\u30c8\u3067\u30d3\u30eb\u30c9\uff09\r\n\r\n### \u30c6\u30b9\u30c8/\u691c\u8a3c\r\n- C++ \u5358\u4f53\u30c6\u30b9\u30c8: `./cpp/build/wiplib_tests`\r\n- \u30b4\u30fc\u30eb\u30c7\u30f3\u30d9\u30af\u30bf\u691c\u8a3c:\r\n  - \u751f\u6210: `python python/tools/generate_golden_vectors.py`\r\n  - \u691c\u8a3c: `cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Debug && cmake --build cpp/build --config Debug && ./cpp/build/wiplib_golden`\r\n\r\n### C++ \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\uff08wiplib-cpp\uff09\r\n\u3053\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u306b\u306f C++20 \u5b9f\u88c5\uff08\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304a\u3088\u3073\u30d1\u30b1\u30c3\u30c8\u30b3\u30fc\u30c7\u30c3\u30af\uff09\u304c\u542b\u307e\u308c\u307e\u3059\u3002\u30d3\u30eb\u30c9\u624b\u9806:\r\n\r\n```bash\r\n# CMake 3.20+ \u3068 C++20 \u5bfe\u5fdc\u30b3\u30f3\u30d1\u30a4\u30e9\u3092\u7528\u610f\u3057\u3066\u304f\u3060\u3055\u3044\r\ncmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Release\r\ncmake --build cpp/build --config Release\r\n\r\n# \u5358\u4f53\u30c6\u30b9\u30c8\uff08\u7c21\u6613\uff09\r\n./cpp/build/wiplib_tests\r\n\r\n# CLI \u30c4\u30fc\u30eb\u5b9f\u884c\u4f8b\uff08Python \u30b5\u30fc\u30d0\u7fa4\u8d77\u52d5\u5f8c\uff09\r\n./cpp/build/wip_client_cli --host 127.0.0.1 --port 4110 --area 130010 --weather --temperature --precipitation\r\n\r\n# \u5ea7\u6a19\u6307\u5b9a\u306e\u4f8b\uff08\u6771\u4eac\uff09\r\n./cpp/build/wip_client_cli --host 127.0.0.1 --port 4110 --coords 35.6895 139.6917 --weather --temperature --precipitation\r\n```\r\n\r\nCLI \u30aa\u30d7\u30b7\u30e7\u30f3:\r\n- `--host`, `--port`: \u63a5\u7d9a\u5148 Weather Server (UDP/4110)\r\n- `--coords <lat> <lon>` \u307e\u305f\u306f `--area <6\u6841\u30b3\u30fc\u30c9>`\r\n- `--weather|--no-weather`, `--temperature|--no-temperature`, `--precipitation`, `--alerts`, `--disaster`, `--day <0-7>`\r\n\r\n\u5099\u8003:\r\n- C++ \u5b9f\u88c5\u306f Python \u5b9f\u88c5\u3068\u540c\u3058\u30ea\u30c8\u30eb\u30a8\u30f3\u30c7\u30a3\u30a2\u30f3\u8868\u73fe\u30fb12bit\u30c1\u30a7\u30c3\u30af\u30b5\u30e0\uff081\u306e\u88dc\u6570\u6298\u8fd4\u3057\uff09\u3067\u52d5\u4f5c\u3057\u307e\u3059\u3002\u76f8\u4e92\u904b\u7528\u3067\u4e0d\u4e00\u81f4\u304c\u3042\u308c\u3070 Issue \u3078\u5831\u544a\u304f\u3060\u3055\u3044\u3002\r\n\r\n### \u30b4\u30fc\u30eb\u30c7\u30f3\u30d9\u30af\u30bf\u751f\u6210\uff08Python \u2192 C++ \u691c\u8a3c\uff09\r\nPython \u5b9f\u88c5\u304b\u3089\u65e2\u77e5\u306e\u30d1\u30b1\u30c3\u30c8\u3092\u751f\u6210\u3057\u3066 C++ \u3067\u30c7\u30b3\u30fc\u30c9\u691c\u8a3c\u3067\u304d\u307e\u3059\u3002\r\n\r\n```bash\r\n# 1) \u30b4\u30fc\u30eb\u30c7\u30f3\u30d9\u30af\u30bf\u3092\u751f\u6210\uff08dist/golden/*.bin\uff09\r\npython python/tools/generate_golden_vectors.py\r\n\r\n# 2) C++ \u5074\u3067\u691c\u8a3c\u5b9f\u884c\r\ncmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Debug\r\ncmake --build cpp/build --config Debug\r\n./cpp/build/wiplib_golden\r\n```\r\n\r\n### \u30bd\u30b1\u30c3\u30c8\u7121\u3057\u306e\u76f8\u4e92\u904b\u7528\u30c6\u30b9\u30c8\r\nC++\u3067\u751f\u6210\u3057\u305f\u30ea\u30af\u30a8\u30b9\u30c8\u3092Python\u304c\u89e3\u91c8\u3001Python\u304c\u751f\u6210\u3057\u305f\u30ec\u30b9\u30dd\u30f3\u30b9\u3092C++\u304c\u89e3\u91c8\u3059\u308b\u30c6\u30b9\u30c8\u3092\u81ea\u52d5\u5b9f\u884c\u3067\u304d\u307e\u3059\u3002\r\n\r\n```bash\r\n# C++\u30c4\u30fc\u30eb\u306e\u30d3\u30eb\u30c9\uff08gen/decode\uff09\r\ncmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Debug\r\ncmake --build cpp/build --config Debug --target wip_packet_gen wip_packet_decode\r\n\r\n# \u30d1\u30b9\u6307\u5b9a\u3057\u3066\u30c6\u30b9\u30c8\u5b9f\u884c\uff08Windows\u306f exe \u62e1\u5f35\u5b50\uff09\r\nexport WIP_CPP_BIN_DIR=cpp/build\r\npython python/tools/interop_no_socket.py\r\n```\r\n\r\n#### CMake \u306a\u3057\u3067\u30d3\u30eb\u30c9\u3059\u308b\u5834\u5408\uff08\u5168OS\u5bfe\u5fdc\uff09\r\n\r\n\u74b0\u5883\u306b CMake \u304c\u7121\u3044\u5834\u5408\u3067\u3082\u3001\u540c\u68b1\u30b9\u30af\u30ea\u30d7\u30c8\u3067\u30d3\u30eb\u30c9\u3067\u304d\u307e\u3059\u3002\r\n\r\n- Windows\uff08MSVC / Developer Command Prompt\uff09\r\n  - `cpp\\tools\\build_no_cmake.bat`\r\n  - \u51fa\u529b: `cpp\\build\\wip_client_cli.exe`, `cpp\\build\\wiplib_tests.exe`\r\n- Windows\uff08MSYS2/MinGW\uff09/ Linux / macOS\uff08clang++/g++\uff09\r\n  - `bash cpp/tools/build_no_cmake.sh`\r\n  - \u51fa\u529b: `cpp/build/wip_client_cli`, `cpp/build/wiplib_tests`\r\n\r\n\u5b9f\u884c\u4f8b:\r\n```bash\r\n# CLI\uff08\u65e2\u5b9a\u30db\u30b9\u30c8\u306b\u63a5\u7d9a\u3059\u308b\u4f8b\uff09\r\n./cpp/build/wip_client_cli --host wip.ncc.onl --port 4110 --area 130010 --weather --temperature\r\n\r\n# \u30c6\u30b9\u30c8\uff08\u30b3\u30fc\u30c7\u30c3\u30af\u306e\u5f80\u5fa9\u78ba\u8a8d\uff09\r\n./cpp/build/wiplib_tests\r\n```\r\n\r\n### \u30ed\u30b0\u51fa\u529b\r\n\u30c7\u30d0\u30c3\u30b0\u30e2\u30fc\u30c9\u3067\u306e\u8a73\u7d30\u30ed\u30b0\u51fa\u529b\uff1a\r\n```python\r\n# \u30b5\u30fc\u30d0\u8d77\u52d5\u6642\u306b\u30c7\u30d0\u30c3\u30b0\u30e2\u30fc\u30c9\u3092\u6709\u52b9\u5316\r\nserver = WeatherServer(debug=True)\r\nclient = WeatherClient(debug=True)\r\n```\r\n\r\n## \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\r\n\r\n### \u30d9\u30f3\u30c1\u30de\u30fc\u30af\u7d50\u679c\r\n- **\u30ec\u30b9\u30dd\u30f3\u30b9\u6642\u9593**: \u5e73\u5747 < 100ms\r\n- **\u30b9\u30eb\u30fc\u30d7\u30c3\u30c8**: > 100 req/sec\r\n - **\u30d1\u30b1\u30c3\u30c8\u30b5\u30a4\u30ba**: \u57fa\u672c16\u30d0\u30a4\u30c8\u3001\u62e1\u5f35\u6642\u6700\u59271023\u30d0\u30a4\u30c8\r\n- **\u540c\u6642\u63a5\u7d9a**: \u6700\u5927100\u63a5\u7d9a\r\n\r\n### \u6700\u9069\u5316\u30dd\u30a4\u30f3\u30c8\r\n- Redis \u30ad\u30e3\u30c3\u30b7\u30e5\u306b\u3088\u308b\u9ad8\u901f\u30c7\u30fc\u30bf\u30a2\u30af\u30bb\u30b9\r\n- \u30d0\u30a4\u30ca\u30ea\u5f62\u5f0f\u306b\u3088\u308b\u52b9\u7387\u7684\u306a\u30c7\u30fc\u30bf\u8ee2\u9001\r\n- \u5206\u6563\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u306b\u3088\u308b\u8ca0\u8377\u5206\u6563\r\n- \u5ea7\u6a19\u89e3\u6c7a\u7d50\u679c\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\r\n\r\n### \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6e2c\u5b9a\r\n\u6027\u80fd\u8a55\u4fa1\u306b\u306f C++ \u5b9f\u88c5\u306e\u30d9\u30f3\u30c1\u30c4\u30fc\u30eb\uff08`cpp/` \u914d\u4e0b\uff09\u3084\u5b9f\u904b\u7528\u74b0\u5883\u3067\u306e\u30e1\u30c8\u30ea\u30af\u30b9\u53ce\u96c6\u3092\u3054\u5229\u7528\u304f\u3060\u3055\u3044\u3002\r\n\r\n## API\u6bd4\u8f03\r\n\r\n\u5916\u90e8\u6c17\u8c61API\u3068\u306e\u6027\u80fd\u6bd4\u8f03\uff08\u30d9\u30f3\u30c1\u30de\u30fc\u30af\u306f\u5225\u9014\u30c4\u30fc\u30eb/\u74b0\u5883\u3067\u5b9f\u65bd\uff09\uff1a\r\n\r\n### \u5bfe\u8c61API\r\n- **Open-Meteo API**: \u7121\u6599\u306e\u6c17\u8c61\u30c7\u30fc\u30bfAPI\r\n- **wttr.in API**: \u30b7\u30f3\u30d7\u30eb\u306a\u5929\u6c17\u60c5\u5831API\r\n- **met.no API**: \u30ce\u30eb\u30a6\u30a7\u30fc\u6c17\u8c61\u7814\u7a76\u6240\u306eAPI\r\n- **\u6c17\u8c61\u5e81API**: \u65e5\u672c\u306e\u516c\u5f0f\u6c17\u8c61\u30c7\u30fc\u30bfAPI\r\n\r\n### \u6bd4\u8f03\u9805\u76ee\r\n- \u30ec\u30b9\u30dd\u30f3\u30b9\u6642\u9593\r\n- \u30b9\u30eb\u30fc\u30d7\u30c3\u30c8\r\n- \u30c7\u30fc\u30bf\u30b5\u30a4\u30ba\r\n- \u540c\u6642\u63a5\u7d9a\u6027\u80fd\r\n- \u6210\u529f\u7387\r\n\r\n### WIP\u306e\u512a\u4f4d\u6027\r\n - **\u8efd\u91cf**: 16\u30d0\u30a4\u30c8\u306e\u5c0f\u3055\u306a\u30d1\u30b1\u30c3\u30c8\u30b5\u30a4\u30ba\r\n- **\u9ad8\u901f**: \u5e73\u5747100ms\u4ee5\u4e0b\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u6642\u9593\r\n- **\u52b9\u7387**: \u30d0\u30a4\u30ca\u30ea\u5f62\u5f0f\u306b\u3088\u308b\u52b9\u7387\u7684\u306a\u30c7\u30fc\u30bf\u8ee2\u9001\r\n- **\u62e1\u5f35\u6027**: \u707d\u5bb3\u60c5\u5831\u30fb\u8b66\u5831\u30c7\u30fc\u30bf\u306e\u7d71\u5408\u914d\u4fe1\r\n\r\n## \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\r\n\r\n### \u5b9f\u88c5\u6e08\u307f\u6a5f\u80fd\r\n- **\u30c1\u30a7\u30c3\u30af\u30b5\u30e0**: \u30d1\u30b1\u30c3\u30c8\u8aa4\u308a\u691c\u51fa\r\n- **\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7**: \u30ea\u30d7\u30ec\u30a4\u653b\u6483\u5bfe\u7b56\r\n- **\u30d1\u30b1\u30c3\u30c8ID**: \u91cd\u8907\u30d1\u30b1\u30c3\u30c8\u691c\u51fa\r\n\r\n### \u63a8\u5968\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\r\n- \u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u306b\u3088\u308b\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\r\n- VPN\u306b\u3088\u308b\u901a\u4fe1\u6697\u53f7\u5316\r\n- \u30ec\u30fc\u30c8\u5236\u9650\u306b\u3088\u308bDoS\u653b\u6483\u5bfe\u7b56\r\n\r\n## \u62e1\u5f35\u6a5f\u80fd\r\n\r\n### Wireshark\u30d7\u30ed\u30c8\u30b3\u30eb\u89e3\u6790\r\n```bash\r\n# Wireshark\u3067\u306e\u30d1\u30b1\u30c3\u30c8\u89e3\u6790\u7528 Lua \u30b9\u30af\u30ea\u30d7\u30c8\r\n# lua/wireshark.lua \u3092 Wireshark \u306e\u30d7\u30e9\u30b0\u30a4\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306b\u914d\u7f6e\r\n```\r\n\r\n### \u81ea\u52d5\u30c7\u30fc\u30bf\u66f4\u65b0\r\n```bash\r\n# \u6c17\u8c61\u30c7\u30fc\u30bf\u306e\u5b9a\u671f\u66f4\u65b0\u30b9\u30af\u30ea\u30d7\u30c8\uff08\u81ea\u52d5\u5b9f\u884c\uff09\r\n# \u30b5\u30fc\u30d0\u30fc\u8d77\u52d5\u6642\u306b\u81ea\u52d5\u7684\u306b\u958b\u59cb\u3055\u308c\u307e\u3059\r\n```\r\n\r\n### \u30ad\u30e3\u30c3\u30b7\u30e5\u7ba1\u7406\r\n- Redis \u306b\u3088\u308b\u9ad8\u901f\u30ad\u30e3\u30c3\u30b7\u30e5\r\n- \u5730\u57df\u30b3\u30fc\u30c9\u30ad\u30e3\u30c3\u30b7\u30e5\uff08\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074: `src/WIPClientPy/coordinate_cache.json`\uff09\r\n- \u6c17\u8c61\u30c7\u30fc\u30bf\u30ad\u30e3\u30c3\u30b7\u30e5\uff08TTL: 1\u6642\u9593\uff09\r\n- \u5404\u30ad\u30e3\u30c3\u30b7\u30e5\u306f\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306e `enable_*_cache` \u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u6709\u52b9/\u7121\u52b9\u3092\u5207\u308a\u66ff\u3048\u53ef\u80fd\r\n- WIPClientPy \u306e\u5ea7\u6a19\u30ad\u30e3\u30c3\u30b7\u30e5\u306f `src/WIPClientPy/config.ini` \u306e\r\n  `enable_coordinate_cache` \u3067\u30aa\u30f3/\u30aa\u30d5\u3092\u8a2d\u5b9a\r\n\r\n## \u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0\r\n\r\n### \u3088\u304f\u3042\u308b\u554f\u984c\r\n\r\n#### 1. \u63a5\u7d9a\u30a8\u30e9\u30fc\r\n```bash\r\n# \u30b5\u30fc\u30d0\u304c\u8d77\u52d5\u3057\u3066\u3044\u308b\u304b\u78ba\u8a8d\r\nnetstat -an | grep 4110\r\n\r\n# \u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\u8a2d\u5b9a\u78ba\u8a8d\r\n# Windows: Windows Defender \u30d5\u30a1\u30a4\u30a2\u30a6\u30a9\u30fc\u30eb\r\n# Linux: iptables -L\r\n```\r\n\r\n#### 2. \u30d1\u30b1\u30c3\u30c8\u89e3\u6790\u30a8\u30e9\u30fc\r\n```python\r\n# \u30c7\u30d0\u30c3\u30b0\u30e2\u30fc\u30c9\u3067\u30d1\u30b1\u30c3\u30c8\u5185\u5bb9\u78ba\u8a8d\uff08Python \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\uff09\r\nfrom WIPCommonPy.clients.weather_client import WeatherClient\r\nclient = WeatherClient(debug=True)\r\n# \u4ee5\u964d\u3001\u901a\u5e38\u306e API \u547c\u3073\u51fa\u3057\u3067\u8a73\u7d30\u30ed\u30b0\u304c\u51fa\u529b\u3055\u308c\u307e\u3059\r\n```\r\n\r\n#### 3. \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u554f\u984c\r\n- \u30dc\u30c8\u30eb\u30cd\u30c3\u30af\u306e\u5207\u308a\u5206\u3051\u306b C++ \u30d9\u30f3\u30c1\uff08`cpp/`\uff09\u3084\u5916\u90e8\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002\r\n\r\n### \u30ed\u30b0\u30ec\u30d9\u30eb\r\n- `[INFO]`: \u4e00\u822c\u7684\u306a\u60c5\u5831\r\n- `[ERROR]`: \u30a8\u30e9\u30fc\u60c5\u5831\r\n- `[PERF]`: \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u95a2\u9023\r\n- `[DEBUG]`: \u30c7\u30d0\u30c3\u30b0\u60c5\u5831\r\n\r\n## \u6280\u8853\u4ed5\u69d8\u8a73\u7d30\r\n\r\n### \u30d7\u30ed\u30c8\u30b3\u30eb\u30b9\u30bf\u30c3\u30af\r\n```\r\n+------------------+\r\n| WIP Application  |\r\n+------------------+\r\n| UDP              |\r\n+------------------+\r\n| IP               |\r\n+------------------+\r\n| Ethernet         |\r\n+------------------+\r\n```\r\n\r\n### \u30c7\u30fc\u30bf\u30d5\u30ed\u30fc\r\n1. **\u30af\u30e9\u30a4\u30a2\u30f3\u30c8**: \u5ea7\u6a19\u307e\u305f\u306f\u30a8\u30ea\u30a2\u30b3\u30fc\u30c9\u3067\u30ea\u30af\u30a8\u30b9\u30c8\r\n2. **Weather Server**: \u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9069\u5207\u306a\u30b5\u30fc\u30d0\u306b\u8ee2\u9001\r\n3. **Location Server**: \u5ea7\u6a19\u3092\u5730\u57df\u30b3\u30fc\u30c9\u306b\u5909\u63db\r\n4. **Query Server**: \u6c17\u8c61\u5e81\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u30fb\u51e6\u7406\r\n5. **\u30ec\u30b9\u30dd\u30f3\u30b9**: \u6c17\u8c61\u30c7\u30fc\u30bf\u3092\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306b\u8fd4\u9001\r\n\r\n### \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\r\n- **\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8**: 10\u79d2\u3067\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\r\n- **\u30c1\u30a7\u30c3\u30af\u30b5\u30e0\u30a8\u30e9\u30fc**: \u30d1\u30b1\u30c3\u30c8\u7834\u68c4\r\n- **\u4e0d\u6b63\u30d5\u30a9\u30fc\u30de\u30c3\u30c8**: \u30a8\u30e9\u30fc\u30ec\u30b9\u30dd\u30f3\u30b9\r\n- **\u30b5\u30fc\u30d0\u30a8\u30e9\u30fc**: \u9069\u5207\u306a\u30a8\u30e9\u30fc\u30b3\u30fc\u30c9\u8fd4\u9001\r\n\r\n## \u30e9\u30a4\u30bb\u30f3\u30b9\r\n\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306fMIT\u30e9\u30a4\u30bb\u30f3\u30b9\u306e\u4e0b\u3067\u516c\u958b\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u8a73\u3057\u304f\u306f [LICENSE](LICENSE) \u3092\u3054\u89a7\u304f\u3060\u3055\u3044\u3002\r\n\r\n## \u8ca2\u732e\r\n\r\n### \u8ca2\u732e\u65b9\u6cd5\r\n1. \u3053\u306e\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u30d5\u30a9\u30fc\u30af\r\n2. \u6a5f\u80fd\u30d6\u30e9\u30f3\u30c1\u3092\u4f5c\u6210 (`git checkout -b feature/amazing-feature`)\r\n3. \u5909\u66f4\u3092\u30b3\u30df\u30c3\u30c8 (`git commit -m 'Add amazing feature'`)\r\n4. \u30d6\u30e9\u30f3\u30c1\u306b\u30d7\u30c3\u30b7\u30e5 (`git push origin feature/amazing-feature`)\r\n5. \u30d7\u30eb\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u4f5c\u6210\r\n\r\n### \u958b\u767a\u30ac\u30a4\u30c9\u30e9\u30a4\u30f3\r\n- \u30b3\u30fc\u30c9\u30b9\u30bf\u30a4\u30eb: PEP 8\u6e96\u62e0\r\n- \u30c6\u30b9\u30c8: \u65b0\u6a5f\u80fd\u306b\u306f\u5fc5\u305a\u30c6\u30b9\u30c8\u3092\u8ffd\u52a0\r\n- \u30c9\u30ad\u30e5\u30e1\u30f3\u30c8: \u5909\u66f4\u5185\u5bb9\u3092README\u306b\u53cd\u6620\r\n- \u30c7\u30d0\u30c3\u30b0: \u30c7\u30d0\u30c3\u30b0\u30c4\u30fc\u30eb\u3067\u306e\u691c\u8a3c\u3092\u5b9f\u65bd\r\n- \u958b\u767a\u30c1\u30fc\u30e0: NCC\u4ee3\u8868\r\n\r\n## \u30b5\u30dd\u30fc\u30c8\r\n\r\n\r\n\r\n### \u30b5\u30dd\u30fc\u30c8\u7bc4\u56f2\r\n- \u30d7\u30ed\u30c8\u30b3\u30eb\u4ed5\u69d8\u306b\u95a2\u3059\u308b\u8cea\u554f\r\n- \u5b9f\u88c5\u4e0a\u306e\u554f\u984c\r\n- \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\r\n- \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u554f\u984c\r\n\r\n### \u30ec\u30b9\u30dd\u30f3\u30b9\u6642\u9593\r\n- \u91cd\u8981\u306a\u554f\u984c: 24\u6642\u9593\u4ee5\u5185\r\n- \u4e00\u822c\u7684\u306a\u8cea\u554f: 3\u55b6\u696d\u65e5\u4ee5\u5185\r\n- \u6a5f\u80fd\u8981\u6c42: 1\u9031\u9593\u4ee5\u5185\r\n\r\n## \u95a2\u9023\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\r\n\r\n### \u6280\u8853\u6587\u66f8\r\n- [docs/project_detail.md](docs/project_detail.md) - \u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u8a73\u7d30\r\n- [docs/protocol_format.xlsx](docs/protocol_format.xlsx) - \u30d1\u30b1\u30c3\u30c8\u5f62\u5f0f\u8a73\u7d30\r\n\r\n### \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\r\n- [yml/env311.yml](yml/env311.yml) - Conda\u74b0\u5883\u8a2d\u5b9a\r\n- [weather_code.json](weather_code.json) - \u5929\u6c17\u30b3\u30fc\u30c9\u5b9a\u7fa9\r\n- [start_servers.bat](start_servers.bat) - \u30b5\u30fc\u30d0\u8d77\u52d5\u30b9\u30af\u30ea\u30d7\u30c8\r\n\r\n## \u66f4\u65b0\u5c65\u6b74\r\n\r\n### v1.0.0 (2025-06-01)\r\n- \u521d\u56de\u30ea\u30ea\u30fc\u30b9\r\n- \u57fa\u672c\u30d7\u30ed\u30c8\u30b3\u30eb\u5b9f\u88c5\r\n- 3\u30b5\u30fc\u30d0\u69cb\u6210\u306e\u5b9f\u88c5\r\n- \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u30e9\u30a4\u30d6\u30e9\u30ea\r\n- \u30c7\u30d0\u30c3\u30b0\u30c4\u30fc\u30eb\u7fa4\r\n- \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u30c6\u30b9\u30c8\r\n\r\n#### \u4e3b\u8981\u6a5f\u80fd\r\n- NTP\u30d9\u30fc\u30b9\u306eUDP\u30d7\u30ed\u30c8\u30b3\u30eb\r\n - 16\u30d0\u30a4\u30c8\u8efd\u91cf\u30d1\u30b1\u30c3\u30c8\r\n- \u5ea7\u6a19\u89e3\u6c7a\u6a5f\u80fd\r\n- \u6c17\u8c61\u30c7\u30fc\u30bf\u914d\u4fe1\r\n- \u707d\u5bb3\u60c5\u5831\u914d\u4fe1\r\n- \u62e1\u5f35\u30d5\u30a3\u30fc\u30eb\u30c9\u30b5\u30dd\u30fc\u30c8\r\n\r\n#### \u6280\u8853\u7684\u6539\u5584\r\n- \u30d0\u30a4\u30ca\u30ea\u5f62\u5f0f\u3067\u306e\u30c7\u30fc\u30bf\u8ee2\u9001\r\n- Redis \u30ad\u30e3\u30c3\u30b7\u30e5\u30b7\u30b9\u30c6\u30e0\r\n- \u5206\u6563\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\r\n- \u5305\u62ec\u7684\u306a\u30c7\u30d0\u30c3\u30b0\u30c4\u30fc\u30eb\r\n- \u5916\u90e8API\u6027\u80fd\u6bd4\u8f03\r\n\r\n---\r\n\r\n**WIP (Weather Information Protocol)** - \u8efd\u91cf\u3067\u52b9\u7387\u7684\u306a\u6c17\u8c61\u30c7\u30fc\u30bf\u8ee2\u9001\u30d7\u30ed\u30c8\u30b3\u30eb\r\n\r\n\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u8a73\u7d30\u60c5\u5831\u3084\u6700\u65b0\u306e\u66f4\u65b0\u306b\u3064\u3044\u3066\u306f\u3001[GitHub \u30ea\u30dd\u30b8\u30c8\u30ea](https://github.com/U22-2025/WIP)\u3092\u3054\u78ba\u8a8d\u304f\u3060\u3055\u3044\u3002\r\n",
    "bugtrack_url": null,
    "license": "MIT License\r\n        \r\n        Copyright (c) 2025 WIP Project\r\n        \r\n        Permission is hereby granted, free of charge, to any person obtaining a copy\r\n        of this software and associated documentation files (the \"Software\"), to deal\r\n        in the Software without restriction, including without limitation the rights\r\n        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n        copies of the Software, and to permit persons to whom the Software is\r\n        furnished to do so, subject to the following conditions:\r\n        \r\n        The above copyright notice and this permission notice shall be included in all\r\n        copies or substantial portions of the Software.\r\n        \r\n        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\n        SOFTWARE.\r\n        ",
    "summary": "Awesome toolkit for weather data (client\u2011side).",
    "version": "0.1.0",
    "project_urls": {
        "Homepage": "https://github.com/U22-2025/WIP"
    },
    "split_keywords": [
        "weather",
        " protocol",
        " data",
        " disaster",
        " alert",
        " japan",
        " toolkit"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "391d41c40c84f4fde3118bca16ea1fcfcdc890cd4c53afb2b909f227bbf3dda0",
                "md5": "3d71d335e17900580f00847c15f52bd6",
                "sha256": "af29fe7978e6424726abb5b664f83152d7457e8ee8e80f2755cad23184a8d655"
            },
            "downloads": -1,
            "filename": "wiplib-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3d71d335e17900580f00847c15f52bd6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 195971,
            "upload_time": "2025-09-03T06:58:27",
            "upload_time_iso_8601": "2025-09-03T06:58:27.750353Z",
            "url": "https://files.pythonhosted.org/packages/39/1d/41c40c84f4fde3118bca16ea1fcfcdc890cd4c53afb2b909f227bbf3dda0/wiplib-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2abf0b0e2a42bda1dd7a26569f760a325b689caaa9bb7cbb98b1180cf956ff31",
                "md5": "bed8f5772764ffb91026aa3cde97a644",
                "sha256": "6ad222301ca90cbdb9f952731aee8ad7a99303f00cb1788652bf408b36c20e7f"
            },
            "downloads": -1,
            "filename": "wiplib-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "bed8f5772764ffb91026aa3cde97a644",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 145330,
            "upload_time": "2025-09-03T06:58:29",
            "upload_time_iso_8601": "2025-09-03T06:58:29.696370Z",
            "url": "https://files.pythonhosted.org/packages/2a/bf/0b0e2a42bda1dd7a26569f760a325b689caaa9bb7cbb98b1180cf956ff31/wiplib-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-03 06:58:29",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "U22-2025",
    "github_project": "WIP",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "aioquic",
            "specs": []
        },
        {
            "name": "fastapi",
            "specs": []
        },
        {
            "name": "geopy",
            "specs": []
        },
        {
            "name": "hypercorn",
            "specs": []
        },
        {
            "name": "psycopg2",
            "specs": []
        },
        {
            "name": "python-dateutil",
            "specs": []
        },
        {
            "name": "python-dotenv",
            "specs": []
        },
        {
            "name": "quart",
            "specs": []
        },
        {
            "name": "redis",
            "specs": []
        },
        {
            "name": "requests",
            "specs": []
        },
        {
            "name": "schedule",
            "specs": []
        },
        {
            "name": "uvicorn",
            "specs": []
        }
    ],
    "lcname": "wiplib"
}
        
Elapsed time: 1.34951s