esp32io 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esp32io/__init__.py +13 -0
- esp32io/client.py +218 -0
- esp32io/exceptions.py +11 -0
- esp32io/protocol.py +1 -0
- esp32io-0.1.0.dist-info/METADATA +198 -0
- esp32io-0.1.0.dist-info/RECORD +9 -0
- esp32io-0.1.0.dist-info/WHEEL +5 -0
- esp32io-0.1.0.dist-info/licenses/LICENSE +21 -0
- esp32io-0.1.0.dist-info/top_level.txt +1 -0
esp32io/__init__.py
ADDED
esp32io/client.py
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import serial
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
from typing import Any, Dict, Optional
|
|
5
|
+
|
|
6
|
+
from .exceptions import (
|
|
7
|
+
ESP32IOError,
|
|
8
|
+
ESP32IOTimeoutError,
|
|
9
|
+
ESP32IOProtocolError,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
class ESP32IO:
|
|
13
|
+
"""
|
|
14
|
+
ESP32 と JSON ベースのシリアルプロトコルで通信するクライアント。
|
|
15
|
+
|
|
16
|
+
想定プロトコル:
|
|
17
|
+
PC -> ESP32: {"cmd": "read_di", "pin_id": 0}
|
|
18
|
+
ESP32 -> PC: {"status": "ok", "value": 1}
|
|
19
|
+
|
|
20
|
+
PC -> ESP32: {"cmd": "set_pwm", "pin_id": 0, "duty": 128}
|
|
21
|
+
ESP32 -> PC: {"status": "ok"}
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
port: str,
|
|
27
|
+
baud: int = 115200,
|
|
28
|
+
timeout: float = 2.0,
|
|
29
|
+
debug: bool = False,
|
|
30
|
+
recv_timeout: Optional[float] = None,
|
|
31
|
+
) -> None:
|
|
32
|
+
"""
|
|
33
|
+
:param port: 例: "COM5" や "/dev/ttyUSB0"
|
|
34
|
+
:param baud: ボーレート (デフォルト: 115200)
|
|
35
|
+
:param timeout: pyserial の read タイムアウト秒数
|
|
36
|
+
:param debug: True にすると送受信ログを表示
|
|
37
|
+
:param recv_timeout: _safe_recv 内での最大待ち時間(秒)。
|
|
38
|
+
None の場合は無制限ループ(pyserial の timeout に依存)
|
|
39
|
+
"""
|
|
40
|
+
self.debug = debug
|
|
41
|
+
self.ser = serial.Serial(port, baudrate=baud, timeout=timeout)
|
|
42
|
+
self.recv_timeout = recv_timeout
|
|
43
|
+
|
|
44
|
+
# ESP32 側のリセット直後のゴミを捨てる
|
|
45
|
+
time.sleep(0.5)
|
|
46
|
+
self.ser.reset_input_buffer()
|
|
47
|
+
|
|
48
|
+
# ウォームアップ: ping を投げて応答を捨てる(失敗しても無視)
|
|
49
|
+
try:
|
|
50
|
+
self._send({"cmd": "ping"})
|
|
51
|
+
self._safe_recv()
|
|
52
|
+
except Exception:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
# ------------------------------
|
|
56
|
+
# 内部ユーティリティ
|
|
57
|
+
# ------------------------------
|
|
58
|
+
def _log(self, *args: Any) -> None:
|
|
59
|
+
if self.debug:
|
|
60
|
+
print("[ESP32IO]", *args)
|
|
61
|
+
|
|
62
|
+
def _send(self, obj: Dict[str, Any]) -> None:
|
|
63
|
+
"""JSON オブジェクトを 1 行の JSON として送信する"""
|
|
64
|
+
line = json.dumps(obj, separators=(",", ":")) + "\n"
|
|
65
|
+
self._log("SEND:", line.strip())
|
|
66
|
+
data = line.encode("utf-8")
|
|
67
|
+
|
|
68
|
+
total = 0
|
|
69
|
+
while total < len(data):
|
|
70
|
+
written = self.ser.write(data[total:])
|
|
71
|
+
if written == 0:
|
|
72
|
+
raise ESP32IOProtocolError("Failed to write to serial port")
|
|
73
|
+
total += written
|
|
74
|
+
|
|
75
|
+
def _safe_recv(self) -> Dict[str, Any]:
|
|
76
|
+
"""
|
|
77
|
+
空行を無視し、JSON を返すまで待つ。
|
|
78
|
+
- status=error の場合は ESP32IOError を送出
|
|
79
|
+
- recv_timeout を超えた場合は ESP32IOTimeoutError を送出
|
|
80
|
+
- 不正 JSON の場合は ESP32IOProtocolError を送出
|
|
81
|
+
"""
|
|
82
|
+
start = time.perf_counter()
|
|
83
|
+
|
|
84
|
+
while True:
|
|
85
|
+
if self.recv_timeout is not None:
|
|
86
|
+
if (time.perf_counter() - start) > self.recv_timeout:
|
|
87
|
+
raise ESP32IOTimeoutError("Timeout waiting for response from ESP32")
|
|
88
|
+
|
|
89
|
+
line_bytes = self.ser.readline()
|
|
90
|
+
if not line_bytes:
|
|
91
|
+
# pyserial の timeout による空読み。recv_timeout が None なら継続。
|
|
92
|
+
if self.recv_timeout is None:
|
|
93
|
+
continue
|
|
94
|
+
# recv_timeout 管理は上の if でやっているのでここでは単に continue
|
|
95
|
+
continue
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
line = line_bytes.decode("utf-8", errors="replace").strip()
|
|
99
|
+
except UnicodeDecodeError as e:
|
|
100
|
+
raise ESP32IOProtocolError(f"Invalid UTF-8 from ESP32: {line_bytes!r}") from e
|
|
101
|
+
|
|
102
|
+
if not line:
|
|
103
|
+
# 空行は無視
|
|
104
|
+
continue
|
|
105
|
+
|
|
106
|
+
self._log("RECV:", line)
|
|
107
|
+
|
|
108
|
+
# JSON パース
|
|
109
|
+
try:
|
|
110
|
+
data = json.loads(line)
|
|
111
|
+
except json.JSONDecodeError as e:
|
|
112
|
+
raise ESP32IOProtocolError(f"Invalid JSON from ESP32: {line}") from e
|
|
113
|
+
|
|
114
|
+
# エラー応答なら例外
|
|
115
|
+
if data.get("status") == "error":
|
|
116
|
+
code = data.get("code", "UNKNOWN")
|
|
117
|
+
detail = data.get("detail", "")
|
|
118
|
+
raise ESP32IOError(f"{code}: {detail}")
|
|
119
|
+
|
|
120
|
+
# 正常応答
|
|
121
|
+
return data
|
|
122
|
+
|
|
123
|
+
def command(self, cmd: str, **kwargs: Any) -> Dict[str, Any]:
|
|
124
|
+
"""
|
|
125
|
+
任意のコマンドを送信し、JSON 応答を返す低レベル API。
|
|
126
|
+
|
|
127
|
+
:param cmd: "read_di" など
|
|
128
|
+
:param kwargs: 追加パラメータ
|
|
129
|
+
:return: ESP32 からの JSON 応答
|
|
130
|
+
"""
|
|
131
|
+
req: Dict[str, Any] = {"cmd": cmd}
|
|
132
|
+
req.update(kwargs)
|
|
133
|
+
self._send(req)
|
|
134
|
+
return self._safe_recv()
|
|
135
|
+
|
|
136
|
+
# ------------------------------
|
|
137
|
+
# 基本4コマンド(公開 API)
|
|
138
|
+
# ------------------------------
|
|
139
|
+
def read_di(self, pin_id: int) -> int:
|
|
140
|
+
"""
|
|
141
|
+
デジタル入力を読む。
|
|
142
|
+
|
|
143
|
+
:param pin_id: ピン番号(ESP32 側の定義に依存)
|
|
144
|
+
:return: 0 or 1
|
|
145
|
+
"""
|
|
146
|
+
res = self.command("read_di", pin_id=pin_id)
|
|
147
|
+
value = res.get("value")
|
|
148
|
+
if not isinstance(value, int):
|
|
149
|
+
raise ESP32IOProtocolError(f"Invalid read_di response: {res}")
|
|
150
|
+
return value
|
|
151
|
+
|
|
152
|
+
def set_do(self, pin_id: int, value: int) -> Dict[str, Any]:
|
|
153
|
+
"""
|
|
154
|
+
デジタル出力を書き込む。
|
|
155
|
+
|
|
156
|
+
:param pin_id: ピン番号
|
|
157
|
+
:param value: 0 or 1
|
|
158
|
+
:return: ESP32 の生 JSON 応答
|
|
159
|
+
"""
|
|
160
|
+
return self.command("set_do", pin_id=pin_id, value=value)
|
|
161
|
+
|
|
162
|
+
def read_adc(self, pin_id: int) -> int:
|
|
163
|
+
"""
|
|
164
|
+
ADC を読む。
|
|
165
|
+
|
|
166
|
+
:param pin_id: ピン番号
|
|
167
|
+
:return: ADC 値(0〜4095 など、ESP32 側の仕様に依存)
|
|
168
|
+
"""
|
|
169
|
+
res = self.command("read_adc", pin_id=pin_id)
|
|
170
|
+
value = res.get("value")
|
|
171
|
+
if not isinstance(value, int):
|
|
172
|
+
raise ESP32IOProtocolError(f"Invalid read_adc response: {res}")
|
|
173
|
+
return value
|
|
174
|
+
|
|
175
|
+
def set_pwm(self, pin_id: int, duty: int) -> Dict[str, Any]:
|
|
176
|
+
"""
|
|
177
|
+
PWM デューティを設定する。
|
|
178
|
+
|
|
179
|
+
:param pin_id: ピン番号
|
|
180
|
+
:param duty: デューティ値(0〜255 など、ESP32 側の仕様に依存)
|
|
181
|
+
:return: ESP32 の生 JSON 応答
|
|
182
|
+
"""
|
|
183
|
+
return self.command("set_pwm", pin_id=pin_id, duty=duty)
|
|
184
|
+
|
|
185
|
+
# ------------------------------
|
|
186
|
+
# 全データ取得コマンド(公開 API)
|
|
187
|
+
# ------------------------------
|
|
188
|
+
def get_io_state(self):
|
|
189
|
+
"""
|
|
190
|
+
ESP32 の全 I/O 状態をまとめて取得する。
|
|
191
|
+
戻り値:
|
|
192
|
+
dio_in : list[int] (len=6)
|
|
193
|
+
dio_out : list[int] (len=6)
|
|
194
|
+
adc : list[int] (len=2)
|
|
195
|
+
pwm : list[int] (len=2)
|
|
196
|
+
"""
|
|
197
|
+
res = self.command("get_io_state")
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
"dio_in": list(res["dio_in"]),
|
|
201
|
+
"dio_out": list(res["dio_out"]),
|
|
202
|
+
"adc": list(res["adc"]),
|
|
203
|
+
"pwm": list(res["pwm"]),
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# ------------------------------
|
|
207
|
+
# 後片付け
|
|
208
|
+
# ------------------------------
|
|
209
|
+
def close(self) -> None:
|
|
210
|
+
"""シリアルポートを閉じる"""
|
|
211
|
+
if self.ser and self.ser.is_open:
|
|
212
|
+
self.ser.close()
|
|
213
|
+
|
|
214
|
+
def __del__(self) -> None:
|
|
215
|
+
try:
|
|
216
|
+
self.close()
|
|
217
|
+
except Exception:
|
|
218
|
+
pass
|
esp32io/exceptions.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class ESP32IOError(Exception):
|
|
2
|
+
"""ESP32 が status=error を返したときの例外"""
|
|
3
|
+
pass
|
|
4
|
+
|
|
5
|
+
class ESP32IOTimeoutError(TimeoutError):
|
|
6
|
+
"""ESP32 からの応答がタイムアウトしたときの例外"""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
class ESP32IOProtocolError(RuntimeError):
|
|
10
|
+
"""ESP32 から不正な JSON や予期しない応答が返ったときの例外"""
|
|
11
|
+
pass
|
esp32io/protocol.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# 機能拡張用
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: esp32io
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ESP32IO is a Python API that turns an ESP32‑S3 into a USB‑connected I/O device.
|
|
5
|
+
Author: Noritama-Lab
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/Noritama-Lab/esp32io-api
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: System :: Hardware
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: pyserial>=3.5
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# ESP32IO Python API
|
|
26
|
+
日本語 / English
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 🇯🇵 ESP32IO Python API
|
|
31
|
+
|
|
32
|
+
ESP32IO は、ESP32‑S3 を USB で接続するだけで I/O デバイスとして扱える Python API です。
|
|
33
|
+
ESP32‑S3 側のファームウェアと組み合わせることで、JSON コマンドを意識せずに Python から I/O を安全かつ直感的に操作できます。
|
|
34
|
+
|
|
35
|
+
### 特徴
|
|
36
|
+
|
|
37
|
+
- USB シリアル経由で I/O を制御
|
|
38
|
+
- JSON ベースの通信プロトコルを API 内部で抽象化
|
|
39
|
+
- ADC / PWM / DIO(入力・出力)を Python から簡単に操作
|
|
40
|
+
- エラー処理・タイムアウト処理を統一
|
|
41
|
+
- 全 I/O 状態を取得できる get_io_state()
|
|
42
|
+
- 初回動作確認用のサンプルコード付き
|
|
43
|
+
|
|
44
|
+
### リポジトリ構成
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
esp32io-api/
|
|
48
|
+
├── esp32io/
|
|
49
|
+
│ ├── __init__.py
|
|
50
|
+
│ ├── client.py
|
|
51
|
+
│ ├── exceptions.py
|
|
52
|
+
│ └── protocol.py
|
|
53
|
+
├── esp32io.egg-info
|
|
54
|
+
├── examples
|
|
55
|
+
│ └── samples.py
|
|
56
|
+
├── pyproject.toml
|
|
57
|
+
├── LICENSE
|
|
58
|
+
└── README.md
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 主なメソッド
|
|
62
|
+
|
|
63
|
+
- read_di(pin_id) — デジタル入力
|
|
64
|
+
- set_do(pin_id, value) — デジタル出力
|
|
65
|
+
- read_adc(pin_id) — ADC 読み取り
|
|
66
|
+
- set_pwm(pin_id, duty) — PWM 出力
|
|
67
|
+
- get_io_state() — 全 I/O 状態の取得
|
|
68
|
+
|
|
69
|
+
### 使用例:ADC の値で LED の明るさを制御
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from esp32io import ESP32IO
|
|
73
|
+
import time
|
|
74
|
+
import serial
|
|
75
|
+
|
|
76
|
+
def main():
|
|
77
|
+
try:
|
|
78
|
+
esp = ESP32IO("COM3", debug=False)
|
|
79
|
+
print("ESP32 に接続しました。")
|
|
80
|
+
|
|
81
|
+
while True:
|
|
82
|
+
adc_value = esp.read_adc(0)
|
|
83
|
+
duty = int(adc_value / 4095 * 255)
|
|
84
|
+
esp.set_pwm(0, duty)
|
|
85
|
+
|
|
86
|
+
print(f"ADC={adc_value}, PWM duty={duty}")
|
|
87
|
+
time.sleep(0.05)
|
|
88
|
+
|
|
89
|
+
except serial.SerialException as e:
|
|
90
|
+
print("ERROR: ESP32 に接続できませんでした。")
|
|
91
|
+
print("理由:", e)
|
|
92
|
+
|
|
93
|
+
finally:
|
|
94
|
+
try:
|
|
95
|
+
esp.set_pwm(0, 0)
|
|
96
|
+
except:
|
|
97
|
+
pass
|
|
98
|
+
print("終了しました。PWM を停止しました。")
|
|
99
|
+
|
|
100
|
+
if __name__ == "__main__":
|
|
101
|
+
main()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### ESP32‑S3 ファームウェア
|
|
105
|
+
|
|
106
|
+
この API は、以下のファームウェアと連携して動作します:
|
|
107
|
+
https://github.com/noritama-lab/esp32io-firmware
|
|
108
|
+
|
|
109
|
+
### ライセンス
|
|
110
|
+
|
|
111
|
+
MIT License
|
|
112
|
+
Copyright (c) 2026 Noritama-Lab
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 🇺🇸 ESP32IO Python API
|
|
117
|
+
|
|
118
|
+
ESP32IO is a Python API that turns an ESP32‑S3 into a USB‑connected I/O device.
|
|
119
|
+
With the corresponding firmware, you can control I/O safely and intuitively without handling JSON commands directly.
|
|
120
|
+
|
|
121
|
+
### Features
|
|
122
|
+
|
|
123
|
+
- I/O control over USB serial
|
|
124
|
+
- JSON protocol fully abstracted inside the API
|
|
125
|
+
- Easy access to ADC / PWM / DIO (input/output)
|
|
126
|
+
- Unified error handling and timeout management
|
|
127
|
+
- get_io_state() for full I/O monitoring
|
|
128
|
+
- Includes sample code for quick testing
|
|
129
|
+
|
|
130
|
+
### Repository Structure
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
esp32io-api/
|
|
134
|
+
├── esp32io/
|
|
135
|
+
│ ├── __init__.py
|
|
136
|
+
│ ├── client.py
|
|
137
|
+
│ ├── exceptions.py
|
|
138
|
+
│ └── protocol.py
|
|
139
|
+
├── esp32io.egg-info
|
|
140
|
+
├── examples
|
|
141
|
+
│ └── samples.py
|
|
142
|
+
├── pyproject.toml
|
|
143
|
+
├── LICENSE
|
|
144
|
+
└── README.md
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Main Methods
|
|
148
|
+
|
|
149
|
+
- read_di(pin_id) — Digital input
|
|
150
|
+
- set_do(pin_id, value) — Digital output
|
|
151
|
+
- read_adc(pin_id) — Read ADC
|
|
152
|
+
- set_pwm(pin_id, duty) — PWM output
|
|
153
|
+
- get_io_state() — Get all I/O states
|
|
154
|
+
|
|
155
|
+
### Example: Control LED brightness using ADC input
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from esp32io import ESP32IO
|
|
159
|
+
import time
|
|
160
|
+
import serial
|
|
161
|
+
|
|
162
|
+
def main():
|
|
163
|
+
try:
|
|
164
|
+
esp = ESP32IO("COM3", debug=False)
|
|
165
|
+
print("Connected to ESP32.")
|
|
166
|
+
|
|
167
|
+
while True:
|
|
168
|
+
adc_value = esp.read_adc(0)
|
|
169
|
+
duty = int(adc_value / 4095 * 255)
|
|
170
|
+
esp.set_pwm(0, duty)
|
|
171
|
+
|
|
172
|
+
print(f"ADC={adc_value}, PWM duty={duty}")
|
|
173
|
+
time.sleep(0.05)
|
|
174
|
+
|
|
175
|
+
except serial.SerialException as e:
|
|
176
|
+
print("ERROR: Could not connect to ESP32.")
|
|
177
|
+
print("Reason:", e)
|
|
178
|
+
|
|
179
|
+
finally:
|
|
180
|
+
try:
|
|
181
|
+
esp.set_pwm(0, 0)
|
|
182
|
+
except:
|
|
183
|
+
pass
|
|
184
|
+
print("Finished. PWM stopped.")
|
|
185
|
+
|
|
186
|
+
if __name__ == "__main__":
|
|
187
|
+
main()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### ESP32‑S3 Firmware
|
|
191
|
+
|
|
192
|
+
This API works with the following firmware:
|
|
193
|
+
https://github.com/noritama-lab/esp32io-firmware
|
|
194
|
+
|
|
195
|
+
### License
|
|
196
|
+
|
|
197
|
+
MIT License
|
|
198
|
+
Copyright (c) 2026 Noritama-Lab
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
esp32io/__init__.py,sha256=kRf_jVE90UdfgDNdLGkPzNZZMMeX8BRdHafkc55eAj8,243
|
|
2
|
+
esp32io/client.py,sha256=RO1go-xQOlg065GSHxLLHnvZJpNWZke1L3BhJ36wCmc,7318
|
|
3
|
+
esp32io/exceptions.py,sha256=S3bapZmMTvUoWFPkZ6OYIDccXnoRw92dEUtRtVJE_e0,378
|
|
4
|
+
esp32io/protocol.py,sha256=hYlzZ9X2arcEXs9_Xl6CD5qEjDtuxVvohYBoCsKlwmQ,17
|
|
5
|
+
esp32io-0.1.0.dist-info/licenses/LICENSE,sha256=_-xJy5Ci_fk_7cVE6rgIC23vs9BXFrLWAb9QcH0_4PM,1069
|
|
6
|
+
esp32io-0.1.0.dist-info/METADATA,sha256=BWb78GGqvdC0nmYEia1f3OpKoAulB6NN2AO9GM1EDpk,5421
|
|
7
|
+
esp32io-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
8
|
+
esp32io-0.1.0.dist-info/top_level.txt,sha256=AftDH3OIXC1Ske5FXRY7OFgPb89fSpvy9itBd1DUoI0,8
|
|
9
|
+
esp32io-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Noritama-Lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
esp32io
|