Skip to content

Commit 7e60eb9

Browse files
authored
Merge pull request #28 from jerryneedell/jerryn_wifi
implement wifmanager and update examples
2 parents 11be8ca + c8505f4 commit 7e60eb9

10 files changed

+366
-307
lines changed

adafruit_espatcontrol/adafruit_espatcontrol_requests.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ def request(method, url, data=None, json=None, headers=None, stream=None):
131131
sock.write(bytes(data, 'utf-8'))
132132

133133
line = sock.readline()
134-
#print(line)
135134
line = line.split(None, 2)
136135
status = int(line[1])
137136
reason = ""
@@ -142,7 +141,6 @@ def request(method, url, data=None, json=None, headers=None, stream=None):
142141
if not line or line == b"\r\n":
143142
break
144143

145-
#print(line)
146144
title, content = line.split(b': ', 1)
147145
if title and content:
148146
title = str(title.lower(), 'utf-8')
@@ -157,6 +155,7 @@ def request(method, url, data=None, json=None, headers=None, stream=None):
157155

158156
except OSError:
159157
sock.close()
158+
print("how did we get here")
160159
raise
161160

162161
resp.status_code = status
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
# The MIT License (MIT)
2+
#
3+
# Copyright (c) 2019 Melissa LeBlanc-Williams for Adafruit Industries
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
13+
# all 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
21+
# THE SOFTWARE.
22+
23+
"""
24+
`adafruit_espatcontrol_wifimanager`
25+
================================================================================
26+
27+
WiFi Manager for making ESP32 AT Control as WiFi much easier
28+
29+
* Author(s): Melissa LeBlanc-Williams, ladyada, Jerry Needell
30+
"""
31+
32+
# pylint: disable=no-name-in-module
33+
34+
import adafruit_espatcontrol.adafruit_espatcontrol_requests as requests
35+
36+
class ESPAT_WiFiManager:
37+
"""
38+
A class to help manage the Wifi connection
39+
"""
40+
def __init__(self, esp, secrets, status_pixel=None, attempts=2):
41+
"""
42+
:param ESP_SPIcontrol esp: The ESP object we are using
43+
:param dict secrets: The WiFi and Adafruit IO secrets dict (See examples)
44+
:param status_pixel: (Optional) The pixel device - A NeoPixel or DotStar (default=None)
45+
:type status_pixel: NeoPixel or DotStar
46+
:param int attempts: (Optional) Failed attempts before resetting the ESP32 (default=2)
47+
"""
48+
# Read the settings
49+
self._esp = esp
50+
self.debug = False
51+
self.secrets = secrets
52+
self.attempts = attempts
53+
requests.set_interface(self._esp)
54+
self.statuspix = status_pixel
55+
self.pixel_status(0)
56+
57+
def reset(self):
58+
"""
59+
Perform a hard reset on the ESP
60+
"""
61+
if self.debug:
62+
print("Resetting ESP")
63+
self._esp.hard_reset()
64+
65+
def connect(self):
66+
"""
67+
Attempt to connect to WiFi using the current settings
68+
"""
69+
failure_count = 0
70+
while not self._esp.is_connected:
71+
try:
72+
if self.debug:
73+
print("Connecting to AP...")
74+
self.pixel_status((100, 0, 0))
75+
self._esp.connect(self.secrets)
76+
failure_count = 0
77+
self.pixel_status((0, 100, 0))
78+
except (ValueError, RuntimeError) as error:
79+
print("Failed to connect, retrying\n", error)
80+
failure_count += 1
81+
if failure_count >= self.attempts:
82+
failure_count = 0
83+
self.reset()
84+
continue
85+
86+
def get(self, url, **kw):
87+
"""
88+
Pass the Get request to requests and update Status NeoPixel
89+
90+
:param str url: The URL to retrieve data from
91+
:param dict data: (Optional) Form data to submit
92+
:param dict json: (Optional) JSON data to submit. (Data must be None)
93+
:param dict header: (Optional) Header data to include
94+
:param bool stream: (Optional) Whether to stream the Response
95+
:return: The response from the request
96+
:rtype: Response
97+
"""
98+
if not self._esp.is_connected:
99+
self.connect()
100+
self.pixel_status((0, 0, 100))
101+
return_val = requests.get(url, **kw)
102+
self.pixel_status(0)
103+
return return_val
104+
105+
def post(self, url, **kw):
106+
"""
107+
Pass the Post request to requests and update Status NeoPixel
108+
109+
:param str url: The URL to post data to
110+
:param dict data: (Optional) Form data to submit
111+
:param dict json: (Optional) JSON data to submit. (Data must be None)
112+
:param dict header: (Optional) Header data to include
113+
:param bool stream: (Optional) Whether to stream the Response
114+
:return: The response from the request
115+
:rtype: Response
116+
"""
117+
if not self._esp.is_connected:
118+
self.connect()
119+
self.pixel_status((0, 0, 100))
120+
return_val = requests.post(url, **kw)
121+
return return_val
122+
123+
def put(self, url, **kw):
124+
"""
125+
Pass the put request to requests and update Status NeoPixel
126+
127+
:param str url: The URL to PUT data to
128+
:param dict data: (Optional) Form data to submit
129+
:param dict json: (Optional) JSON data to submit. (Data must be None)
130+
:param dict header: (Optional) Header data to include
131+
:param bool stream: (Optional) Whether to stream the Response
132+
:return: The response from the request
133+
:rtype: Response
134+
"""
135+
if not self._esp.is_connected:
136+
self.connect()
137+
self.pixel_status((0, 0, 100))
138+
return_val = requests.put(url, **kw)
139+
self.pixel_status(0)
140+
return return_val
141+
142+
def patch(self, url, **kw):
143+
"""
144+
Pass the patch request to requests and update Status NeoPixel
145+
146+
:param str url: The URL to PUT data to
147+
:param dict data: (Optional) Form data to submit
148+
:param dict json: (Optional) JSON data to submit. (Data must be None)
149+
:param dict header: (Optional) Header data to include
150+
:param bool stream: (Optional) Whether to stream the Response
151+
:return: The response from the request
152+
:rtype: Response
153+
"""
154+
if not self._esp.is_connected:
155+
self.connect()
156+
self.pixel_status((0, 0, 100))
157+
return_val = requests.patch(url, **kw)
158+
self.pixel_status(0)
159+
return return_val
160+
161+
def delete(self, url, **kw):
162+
"""
163+
Pass the delete request to requests and update Status NeoPixel
164+
165+
:param str url: The URL to PUT data to
166+
:param dict data: (Optional) Form data to submit
167+
:param dict json: (Optional) JSON data to submit. (Data must be None)
168+
:param dict header: (Optional) Header data to include
169+
:param bool stream: (Optional) Whether to stream the Response
170+
:return: The response from the request
171+
:rtype: Response
172+
"""
173+
if not self._esp.is_connected:
174+
self.connect()
175+
self.pixel_status((0, 0, 100))
176+
return_val = requests.delete(url, **kw)
177+
self.pixel_status(0)
178+
return return_val
179+
180+
def ping(self, host, ttl=250):
181+
"""
182+
Pass the Ping request to the ESP32, update Status NeoPixel, return response time
183+
184+
:param str host: The hostname or IP address to ping
185+
:param int ttl: (Optional) The Time To Live in milliseconds for the packet (default=250)
186+
:return: The response time in milliseconds
187+
:rtype: int
188+
"""
189+
if not self._esp.is_connected:
190+
self.connect()
191+
self.pixel_status((0, 0, 100))
192+
response_time = self._esp.ping(host, ttl=ttl)
193+
self.pixel_status(0)
194+
return response_time
195+
196+
def pixel_status(self, value):
197+
"""
198+
Change Status NeoPixel if it was defined
199+
200+
:param value: The value to set the Board's Status NeoPixel to
201+
:type value: int or 3-value tuple
202+
"""
203+
if self.statuspix:
204+
self.statuspix.fill(value)

examples/espatcontrol_aio_post.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@
22
import board
33
import busio
44
from digitalio import DigitalInOut
5-
from adafruit_espatcontrol import adafruit_espatcontrol
6-
from adafruit_espatcontrol import adafruit_espatcontrol_requests as requests
5+
6+
# ESP32 AT
7+
from adafruit_espatcontrol import adafruit_espatcontrol, adafruit_espatcontrol_wifimanager
8+
9+
#Use below for Most Boards
10+
import neopixel
11+
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards
12+
#Uncomment below for ItsyBitsy M4#
13+
#import adafruit_dotstar as dotstar
14+
#status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
715

816

917
# Get wifi details and more from a secrets.py file
@@ -15,9 +23,9 @@
1523

1624

1725
# With a Metro or Feather M4
26+
uart = busio.UART(board.TX, board.RX, timeout=0.1)
1827
resetpin = DigitalInOut(board.D5)
1928
rtspin = DigitalInOut(board.D6)
20-
uart = busio.UART(board.TX, board.RX, timeout=0.1)
2129

2230
# With a Particle Argon
2331
"""
@@ -33,36 +41,31 @@
3341
"""
3442

3543

36-
esp = adafruit_espatcontrol.ESP_ATcontrol(uart, 115200, reset_pin=resetpin,
37-
run_baudrate = 460800, rts_pin=rtspin, debug=True)
38-
print("Resetting ESP module")
39-
esp.hard_reset()
40-
requests.set_interface(esp)
44+
print("ESP AT commands")
45+
esp = adafruit_espatcontrol.ESP_ATcontrol(uart, 115200,
46+
reset_pin=resetpin, rts_pin=rtspin, debug=False)
47+
wifi = adafruit_espatcontrol_wifimanager.ESPAT_WiFiManager(esp, secrets, status_light)
4148

42-
print("Connected to AT software version", esp.get_version())
4349

4450
counter = 0
51+
4552
while True:
4653
try:
47-
# Connect to WiFi if not already
48-
while not esp.is_connected:
49-
print("Connecting...")
50-
esp.connect(secrets)
51-
print("Connected to", esp.remote_AP)
52-
# great, lets get the data
5354
print("Posting data...", end='')
54-
data=counter
55-
feed='test'
56-
payload={'value':data}
57-
response=requests.post(
55+
data = counter
56+
feed = 'test'
57+
payload = {'value':data}
58+
response = wifi.post(
5859
"https://io.adafruit.com/api/v2/"+secrets['aio_username']+"/feeds/"+feed+"/data",
59-
json=payload,headers={bytes("X-AIO-KEY","utf-8"):bytes(secrets['aio_key'],"utf-8")})
60+
json=payload,
61+
headers={bytes("X-AIO-KEY", "utf-8"):bytes(secrets['aio_key'], "utf-8")})
6062
print(response.json())
6163
response.close()
6264
counter = counter + 1
6365
print("OK")
6466
except (ValueError, RuntimeError, adafruit_espatcontrol.OKError) as e:
6567
print("Failed to get data, retrying\n", e)
68+
wifi.reset()
6669
continue
6770
response = None
68-
time.sleep(10)
71+
time.sleep(15)

0 commit comments

Comments
 (0)