低成本小车, esp32, micropython, wifi, 浏览器控制控制(四轮版)

1 篇文章 0 订阅
1 篇文章 0 订阅

 内容

  1. 成品演示
  2. 硬件购买
  3. 软件开发环境
  4. 代码

成品演示

硬件成品        

配置wifi网页
        连接小车上的Wi-Fi页面

         浏览器输入 http://192.168.4.1 设置小车需要连接的Wi-Fi名和密码,让小车连接本地Wi-Fi

        在上图底部可以看到小车获得的Wi-Fi地址 (如192.168.3.90)
        浏览器输入 http://192.168.3.90 得到控制小车的页面 

控制小车网页

硬件连线

硬件购买

硬件购买拼多多页面截图

软件开发环境

下载esp32s2 Micropython 固件,以便运行Python程序
MicroPython - Python for microcontrollers
下载v1.19.1固件,并按上面连接中描述的方法写入到 esp32 S2 mini 中
安装 Thonny, Python IDE for beginners 并把以下本项目的代码通过Thonny 写入Esp32s2

代码

L298N.py


from machine import Pin, PWM

class DCMotor:

	def __init__(self, pin1, pin2, enable_pin, min_duty=400, max_duty=1023, frequency=1023):
		self.pin1 = Pin(pin1, Pin.OUT)
		self.pin2= Pin(pin2, Pin.OUT)
		self.enable_pin = PWM(Pin(enable_pin), frequency)
		self.min_duty = min_duty
		self.max_duty = max_duty
	
	def forward(self, speed):
		self.speed = speed
		self.enable_pin.duty(self.duty_cycle(self.speed))
		self.pin1.value(1)
		self.pin2.value(0)

	def backward(self, speed):
		self.speed = speed
		self.enable_pin.duty(self.duty_cycle(self.speed))
		self.pin1.value(0)
		self.pin2.value(1)

	def stop(self):
		self.enable_pin.duty(0)
		self.pin1.value(0)
		self.pin2.value(0)
				
	def duty_cycle(self, speed):
		if self.speed <= 0:
			self.speed = 0
		if self.speed > 100:
			self.speed = 100
		duty_cycle = int (self.min_duty + (self.max_duty - self.min_duty)*self.speed/100.)
		print((self.max_duty - self.min_duty)*self.speed)
		print((self.max_duty - self.min_duty)*self.speed/100.)
		print(self.min_duty)
		print(self.speed,duty_cycle)
		return duty_cycle

car.py

from L298N import DCMotor
from machine import Pin

class Car:
	def __init__(self, ins, ens):
		self.motor_11 = DCMotor(ins[2],ins[3],ens[1])
		self.motor_12 = DCMotor(ins[6],ins[7],ens[3])
		self.motor_21 = DCMotor(ins[0],ins[1],ens[0])
		self.motor_22 = DCMotor(ins[4],ins[5],ens[2])
		self.stop()

	def stop(self):
		self.motor_11.stop()
		self.motor_12.stop()
		self.motor_21.stop()
		self.motor_22.stop()

	def forward(self, speed):
		self.motor_11.forward(speed)
		self.motor_12.forward(speed)
		self.motor_21.forward(speed)
		self.motor_22.forward(speed)

	def backward(self, speed):
		self.motor_11.backward(speed)
		self.motor_12.backward(speed)
		self.motor_21.backward(speed)
		self.motor_22.backward(speed)

	def right(self, speed):
		self.motor_11.forward(speed)
		self.motor_12.backward(speed)
		self.motor_21.forward(speed)
		self.motor_22.backward(speed)

	def left(self, speed):
		self.motor_11.backward(speed)
		self.motor_12.forward(speed)
		self.motor_21.backward(speed)
		self.motor_22.forward(speed)
		

main.py

from car_ import Car
import time
car = Car(33,35,16,18)
car.stop()

def car_action(act):
	act = act.split('_')
	if len(act)!=2:
		return
	try:
		act, speed = act[0], int(act[1])
	except:
		return
	if act=='forw':
		car.forward(speed)
	if act=='back':
		car.backward(speed)
	if act=='left':
		car.left(speed)
	if act=='right':
		car.right(speed)
	if act=='stop':
		car.stop()

from serv.__main__ import start_server_
from serv.lib.esp32_ import ESP32_
esp32_ = ESP32_()
start_server_(80, 1, esp32_.html_, car_action)

esp32_config.json

{"ap_name": "632-wireless", "ap_pwd":"******", "essid":"小车1", "led_pin":15}

wifi_index.html

<!DOCTYPE html>
<html>
    <head>
        <title>ESP无线网络设置</title>
        <script>
            function connect() {
                let ap_name = document.getElementById("ap_name").value
                let ap_pwd = document.getElementById("ap_pwd").value
                window.location.href = "/?ap_name="+ap_name+"&ap_pwd="+ap_pwd
            }
        </script>
    </head>

    <body>
        <h2>设置无线网络</h2>
        <table border="0" style="background-color: #F0F8FF">
            <tr><td>接入点</td><td><input type="text" id="ap_name" value="%s"/></input></td></tr>
            <tr><td>密码</td><td><input type="password" id="ap_pwd" value="%s"/></input></td></tr>
            <tr><td></td><td><button type="button" onclick=connect()>链接网络</button></td></tr>
        </table>
        <h3 id=msg>当前IP地址: %s</h3>
    </body>
</html>

control_page.html

<!DOCTYPE html>
<html>
    <head>
        <title>小车控制</title>
    </head>

    <script>
        function action(direction) {
            let uin = document.getElementById('input')
            let url = '/home/'+direction+'_'+uin.value
            window.location.href = url
        }
        function onload() {
            let path = window.location.pathname.split('/')
            if (path.length==3) {
                let speed = path[2].split('_')
                if (speed.length==2) {
                    speed = parseInt(speed[1])
                    let uin = document.getElementById('input')
                    uin.value =''+speed
                }
            }
        }
    </script>
    <body onload="onload()">
        <h2>小车控制</h2>
        <form action="demo_form.php">
          速度(0-100): <input type="text" id="input" value="20">
        </form>
        <button onclick='action("forw")'>向前</button><br>
        <button onclick='action("back")'>向后</button><br>
        <button onclick='action("left")'>向左</button><br>
        <button onclick='action("right")'>向右</button><br>
        <button onclick='action("stop")'>停止</button><br>
    </body>
</html>

serv/__init__.py

#

serv/__main__.py


import json, os

_content = ''
with open('control_page.html') as fp:
	_content = fp.read()
_car_action = None

def home(request_, response_, route_args_):
	if 'car_action' in route_args_ and _car_action is not None:
		_car_action(route_args_['car_action'])
	return response_.write_response_OK_(content_type_='text/html', content_=_content, charset_='UTF-8')

rpc_registry = {}
def ajax_(request_, response_, route_args_):
	global rpc_registry
	params_ = request_.params_
	assert 'data' in params_, '服务请求参数中缺少 data'
	data = json.loads(params_['data'])
	assert 'func_name' in data
	assert 'argv' in data
	func_name = data['func_name']
	argv = data['argv']
	assert func_name in rpc_registry, f'服务中没有登记函数 {func_name}, 所有函数: {", ".join(rpc_registry.keys())}'
	res = rpc_registry[func_name](*argv)
	json_ = json.dumps(res)
	return response_.write_response_JSON_OK_(json_)

def start_server_(port_, max_threads_, esp32_html_=None, car_action=None):
	from .lib.http_ import Http_
	http_ = Http_(ip_='0.0.0.0', port_=port_, web_path_='web', max_threads_=max_threads_)
	if car_action is not None:
		global _car_action
		_car_action = car_action
	if esp32_html_ is not None:
		http_.add_route_('/', esp32_html_, client_addr_='192.168.4.')
	http_.add_route_('/ajax', ajax_, 'GET')
	http_.add_route_('/ajax', ajax_, 'POST')
	http_.add_route_('/', home, 'GET')
	http_.add_route_('/home/{car_action}', home, 'GET')
	http_.start_()

if __name__ == '__main__':
	start_server_(80, 100)

serv/lib/__init__.py

#

serv/lib/esp32_.py


# ESP 32
# 这个文件包含两个线程,一个是WIFI链接的,另一个是板上LED的

import machine
import time, network, json
from .http_ import Http_

def time_str_():
	t_ = time.localtime(time.time())
	return '%d/%d/%d %d:%d.%d' % (t_[0], t_[1], t_[2], t_[3], t_[4], t_[5])

class ESP32_:
	def __init__(self):
		self.config = None
		self.load_config()

		self.onboard_led = machine.Pin(self.config['led_pin'], machine.Pin.OUT)

		self.ap_if = network.WLAN(network.AP_IF)
		if self.config is not None:
			if 'essid' in self.config:
				self.ap_if.config(essid=self.config['essid'])
			if 'password' in self.config:
				self.ap_if.config(password=self.config['password'])
		self.ap_if.active(True)
		print('ESP32 本地热点配置:', self.ap_if.ifconfig()) #  IP address, netmask, gateway, DNS

		self.sta_if = network.WLAN(network.STA_IF)
		self.ip_addr = None

		self.is_connected_ = False
		with open('wifi_index.html') as fp:
			self.html_tempt = fp.read()

		if self.config is not None:
			self.connect()

	def load_config(self):
		try:
			with open('esp32_config.json') as fp:
				self.config = json.load(fp)
		except:
			self.config = None

	def save_config(self):
		with open('esp32_config.json', 'w') as fp:
			json.dump(self.config, fp)

	def connect(self, wait_time=60):
		self.onboard_led.on()
		self.sta_if.active(False)
		self.sta_if.active(True)
		self.is_connected_ = False
		try:
			self.sta_if.connect(self.config['ap_name'], self.config['ap_pwd'])
			self.ip_addr = 'ESP32 正在连接 %s ...' % self.config['ap_name']
			print(self.ip_addr)
		except OSError as ex:
			self.ip_addr = 'ESP32 异常 ' + str(ex)
			print(self.ip_addr)
			self.sta_if.active(False)
			self.onboard_led.on()
			return
		start_time_ = time.time()
		while not self.sta_if.isconnected():
			if time.time() - start_time_ > wait_time:
				break
		if self.sta_if.isconnected():
			self.is_connected_ = True
			self.onboard_led.off()
			self.ip_addr = '[%s] %s (%s)' % (self.config['ap_name'], self.sta_if.ifconfig()[0], time_str_())
			print('ESP32 已连接: ', self.ip_addr)
		else:
			self.ip_addr = 'ESP32 未能连接到 %s' % self.config['ap_name']
			print(self.ip_addr)
			self.sta_if.active(False)
			self.onboard_led.on()
	
	def get_html_(self):
		if self.config is None:
			ap_name = ap_pwd = ''
		else:
			ap_name, ap_pwd = self.config['ap_name'], self.config['ap_pwd']
		return self.html_tempt % (ap_name, '', '未连接无线网络' if self.ip_addr is None else self.ip_addr)

	def html_(self, request_, response_, route_args_):
		print('ESP32 连接', request_.addr_)
		params_ = request_.params_
		if 'ap_name' in params_ and 'ap_pwd' in params_:
			if self.config['ap_name'] != params_['ap_name'] or self.config['ap_pwd'] != params_['ap_pwd']:
				self.config['ap_name'] = params_['ap_name']
				self.config['ap_pwd'] = params_['ap_pwd']
				self.save_config()
				self.connect()
			else:
				print('ESP32 与已有网络配置相同:', self.config['ap_name'])
		response_.write_response_OK_(content_type_="text/html", content_=self.get_html_(), charset_='UTF-8')

serv/lib/path_.py


import os

# try:
# 	import machine
# 	is_micropython = True
# except:
# 	is_micropython = False

def flash_size_(flash_):
	statvfs_fields_ = ['bsize', 'frsize', 'blocks', 'bfree', 'bavail', 'files', 'ffree', ]
	info_ = dict(zip(statvfs_fields_, os.statvfs(flash_)))
	return info_['bsize'] * info_['bfree']

def join_(*args):
	if type(args[0]) is bytes:
		return b"/".join(args)
	else:
		return "/".join(args)

def split_(path_):
	if path_ == "":
		return ("", "")
	r_ = path_.rsplit("/", 1)
	if len(r_) == 1:
		return ("", path_)
	head_ = r_[0] #.rstrip("/")
	if not head_:
		head_ = "/"
	return (head_, r_[1])

def splitext_(path_):
	if path_ == "":
		return ("", "")
	r_ = path_.rsplit(".", 1)
	if len(r_) == 1:
		return (path_, "")
	r_[1] = "." + r_[1]
	return (r_[0], r_[1])

def isdir_(path_):
	try:
		mode_ = os.stat(path_)[0]
		return (mode_ & 0o170000) == 0o040000
	except OSError:
		return False

def isfile_(path_):
	try:
		mode_ = os.stat(path_)[0]
		return (mode_ & 0o170000) == 0o100000
	except OSError:
		return False
	
def exists_(path_):
	try:
		os.stat(path_)
		return True
	except:
		return False

def getmtime_(path_):
	return os.stat(path_)[8]

def getsize_(path_):
	return os.stat(path_)[6]

sep_ = '/'



serv/lib/http_.py


import os, socket, gc, json, time, sys
from .path_ import exists_

class Route_:
	def __init__(self, route_, method_, client_addr_, func_, route_args_):
		self.route_ = route_		
		self.method_ = method_	   
		self.client_addr_ = client_addr_		 
		self.func_ = func_		 
		self.route_args_ = route_args_

mime_types_ = {
	".txt"  : "text/plain",
	".htm"  : "text/html",
	".html" : "text/html",
	".css"  : "text/css",
	".csv"  : "text/csv",
	".js"	: "application/javascript",
	".py"   : "application/python",
	".c"   : "application/c",
	".h"   : "application/c",
	".xml"  : "application/xml",
	".xhtml": "application/xhtml+xml",
	".json" : "application/json",
	".zip"  : "application/zip",
	".pdf"  : "application/pdf",
	".ts"	: "application/typescript",
	".woff" : "font/woff",
	".woff2": "font/woff2",
	".ttf"  : "font/ttf",
	".otf"  : "font/otf",
	".jpg"  : "image/jpeg",
	".jpeg" : "image/jpeg",
	".png"  : "image/png",
	".gif"  : "image/gif",
	".svg"  : "image/svg+xml",
	".ico"  : "image/x-icon",
	".mp3"  : "audio/mpeg3",
	".mp4"  : "video/mp4",
}

def get_mime_type_from_filename_(filename_):
	filename_ = filename_.lower()
	for ext_ in mime_types_:
		if filename_.endswith(ext_):
			return mime_types_[ext_]
	return None

# html_escape_chars_ = {
# 	"&": "&amp;",
# 	'"': "&quot;",
# 	"'": "&apos;",
# 	">": "&gt;",
# 	"<": "&lt;"
# }

# def HTML_escape_(s):
# 	return ''.join(html_escape_chars_.get(c, c) for c in s)

def unquote_(s):
	r = str(s).split('%')
	try:
		b = r[0].encode()
		for i in range(1, len(r)):
			try:
				b += bytes([int(r[i][:2], 16)]) + r[i][2:].encode()
			except:
				b += b'%' + r[i].encode()
		return b.decode('UTF-8')
	except:
		return str(s)

def unquote_plus_(s):
	return unquote_(s.replace('+', ' '))

# def exists_(path_):
# 	try:
# 		os.stat(path_)
# 		return True
# 	except:
# 		return False

################################################################################

class Http_:
	STATIC_CONTENT_CACHE_LEVEL = 0
	BACKLOG = 16 # 还没有接手处理或正在进行的连接

	def __init__(self, ip_, port_, web_path_, max_threads_):
		self.server_addr_ = (ip_, port_)
		if web_path_.endswith('/'):
			web_path_ = web_path_[:-1]
		self.web_path_ = web_path_
		self.started_ = False
		self.max_threads_ = max_threads_
		self.thread_count_ = 0
		self.route_handlers_ = []

	def add_route_(self, url_, func_, method_='GET', client_addr_=''):
		if url_.startswith('/'):
			url_ = url_[1:]
		if url_.endswith('/'):
			url_ = url_[:-1]
		route_parts_ = url_.split('/')
		route_args_ = []
		for s in route_parts_:
			if s.startswith('{') and s.endswith('}'):
				route_args_.append(s[1:-1])
		self.route_handlers_.append(Route_(route_parts_, method_, client_addr_, func_, route_args_))

	def get_route_handler_(self, url_, method_, client_addr_):
		if url_.startswith('/'):
			url_ = url_[1:]
		if url_.endswith('/'):
			url_ = url_[:-1]
		route_parts_ = url_.split('/')
		method_ = method_.upper()
		def match_route_parts_(route_parts_, url_):
			if len(route_parts_) != len(url_):
				return None
			args_ = {}
			for up_, u_ in zip(route_parts_, url_):
				if up_.startswith('{') and up_.endswith('}'):
					args_[up_[1:-1]] = u_
				elif up_ != u_:
					return None
			return args_
		for rh_ in self.route_handlers_:
			if rh_.method_ == method_ and client_addr_.startswith(rh_.client_addr_):
				args_ = match_route_parts_(rh_.route_, url_.split('/'))
				if args_ is not None:
					return rh_.func_, args_
		return None, None

	def start_(self):
		assert not self.started_
		self.server_ = socket.socket()
		self.server_.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		self.server_.bind(self.server_addr_)
		self.server_.listen(Http_.BACKLOG)
		self.started_ = True
		while True:
			try:
				client_socket_, client_addr_ = self.server_.accept()
			except KeyboardInterrupt as ex_:
				break
			except Exception as ex_:
				print(ex_.args)
				sys.print_exception(ex_)
				continue
				# if ex_.args and ex_.args[0] == 113: break
				# continue
			if self.max_threads_ == 0:
				self.thread_count_ += 1
				self.client_thread_(client_socket_, client_addr_)
			else:
				import _thread
				try:
					# _thread.start_new_thread(self.client_thread_, (client_socket_, client_addr_))
					self.client_thread_(client_socket_, client_addr_)
					self.thread_count_ += 1
				except OSError as ex:
					print(str(ex))
				while self.thread_count_ >= self.max_threads_:
					time.sleep(0.1)
		self.started_ = False

	def client_thread_(self, client_socket_, client_addr_):
		Request_(self, client_socket_, client_addr_)
		self.thread_count_ -= 1

	def stop_(self):
		if self.started_:
			self.server_.close()

	def is_started_(self):
		return self.started_

	def local_path_from_url_(self, url_):
		if url_[0] == '/':
			url_ = url_[1:]
		if not url_.startswith('web/'):
			return None
		url_ = url_[4:]
		path_ = self.web_path_ + '/' + url_.replace('../', '/')
		if exists_(path_):
			return path_
		return None

################################################################################

def parse_params_(query_, delimitor1_='&', delimitor2_='='):
	params_ = {}
	elements_ = query_.split(delimitor1_)
	for element_ in elements_:
		param_ = element_.split(delimitor2_, 1)
		if len(param_) > 0:
			value_ = param_[1] if len(param_) > 1 else ''
			params_[param_[0]] = value_
	return params_

def http_handle_ex_(ex):
	if hasattr(sys, 'print_exception'):
		sys.print_exception(ex)
	else:
		import traceback
		traceback.print_exc()
		del traceback

class Request_:

	def __init__(self, http_, socket_, addr_):
		socket_.settimeout(2)
		self.http_ = http_
		self.socket_ = socket_
		self.addr_ = addr_
		self.method_ = None
		self.path_ = None
		self.http_version_ = None
		self.params_ = {}
		self.headers_ = {}
		self.content_type_ = None
		self.content_length_ = 0
		
		if hasattr(socket, 'readline'): # MicroPython
			self.socket_file_ = self.socket_
		else: # CPython
			self.socket_file_ = self.socket_.makefile('rwb')

		try:
			response_ = Response_(self)
			if self.parse_first_line_():
				if self.parse_header_():
					self.read_request_posted_form_data_()
					route_handler_, route_args_ = self.http_.get_route_handler_(self.path_, self.method_, self.addr_[0])
					if route_handler_:
						try:
							route_handler_(self, response_, route_args_)
						except Exception as ex_:
							print('Http handler exception in route %s %s\r\n' % (self.method_, self.path_))
							http_handle_ex_(ex_)
							raise ex_
					else:
						self.write_file_(response_)
				else:
					response_.write_response_bad_request_()
		except Exception as ex_:
			http_handle_ex_(ex_)
			response_.write_response_internal_server_error_()
		finally:
			try:
				if self.socket_file_ is not self.socket_:
					self.socket_file_.close()
				self.socket_.close()
			except:
				print('Exception while closing socket_file')
				pass

	def parse_first_line_(self):
		try:
			elements_ = self.socket_file_.readline().decode().strip().split()
			if len(elements_) == 3:
				self.method_  = elements_[0].upper()
				self.path_	= elements_[1]
				self.http_version_ = elements_[2].upper()
				elements_ = self.path_.split('?', 1)
				if len(elements_) > 0:
					self.path_ = unquote_plus_(elements_[0])
				if len(elements_) > 1:
					params_ = parse_params_(elements_[1])
					self.params_ = {unquote_plus_(k):unquote_plus_(v) for k,v in params_.items()}
				return True
		except:
			pass
		return False

	def parse_header_(self):
		while True:
			elements_ = self.socket_file_.readline().decode().strip().split(':', 1)
			if len(elements_) == 2:
				self.headers_[elements_[0].strip().lower()] = elements_[1].strip()
			elif len(elements_) == 1 and len(elements_[0]) == 0:
				if self.method_ == 'POST' or self.method_ == 'PUT':
					self.content_type_   = self.headers_.get("content-type", None)
					self.content_length_ = int(self.headers_.get("content-length", 0))
				return True
			else:
				return False

	def read_request_content_(self, size_=None):
		if size_ is None:
			size_ = self.content_length_
		if size_ > 0:
			try:
				return self.socket_file_.read(size_)
			except:
				pass
		return b''

	def read_request_posted_form_data_(self):
		if 'content-type' not in self.headers_:
			return
		data_ = self.read_request_content_()
		if self.headers_['content-type'] == 'application/x-www-form-urlencoded':
			data_ = data_.decode()
			data_ = parse_params_(data_)
			data_ = {unquote_plus_(k):unquote_plus_(v) for k,v in data_.items()}			
			self.params_.update(data_)
		elif self.headers_['content-type'].startswith('multipart/form-data;'):
			boundary_ = self.headers_['content-type'].split(';')[1].split('=')[1]
			boundary_ = '--' + boundary_
			data_ = data_.split(boundary_.encode())
			data_ = data_[1:-1]
			for d_ in data_:
				d_ = d_[2:-2].split(b'\r\n\r\n')
				assert d_[0].startswith(b'Content-Disposition: form-data; ')
				part1_ = d_[0].decode().split('; ', 1)[1]
				lines_ = part1_.split('\r\n')
				if len(lines_) == 1:
					d1_ = parse_params_(unquote_plus_(lines_[0]), '; ')
					assert len(d1_) == 1 and 'name' in d1_, part1_
					name_ = json.loads(d1_['name'])
					self.params_[name_] = d_[1].decode()
				else:
					assert len(lines_) == 2, part1_
					d1_ = parse_params_(unquote_plus_(lines_[0]), '; ')
					assert len(d1_) == 2 and 'name' in d1_ and 'filename' in d1_, part1_
					name_ = json.loads(d1_['name'])
					filename_ = json.loads(d1_['filename'])
					self.params_[name_] = {'filename':filename_, 'file':d_[1]}
		else:
			assert False, 'Content-type unsupported: %s' % self.headers_['content-type']

	def write_file_(self, response_, path_=None):
		if path_ is None:
			path_ = self.path_
		filepath_ = self.http_.local_path_from_url_(path_)
		if filepath_:
			content_type_ = get_mime_type_from_filename_(filepath_)
			if content_type_:
				if Http_.STATIC_CONTENT_CACHE_LEVEL > 0:
					if Http_.STATIC_CONTENT_CACHE_LEVEL > 1 and 'if-modified-since' in self.headers_ and '__temp__' not in path_:
						response_.write_response_not_modified_()
					else:
						headers_ = { 'Last-Modified': 'Fri, 1 Jan 2021 00:00:00 GMT', \
									'Cache-Control': 'max-age=315360000', \
									'Access-Control-Allow-Origin': '*' }
						response_.write_response_file_(filepath_, content_type_, headers_)
				else:
					response_.write_response_file_(filepath_, content_type_)
			else:
				response_.write_response_forbidden_()
		else:
			response_.write_response_not_found_()

################################################################################

http_response_codes_ = {
	200: ('OK', 'Request fulfilled, document follows'),
	302: ('Found', 'Object moved temporarily -- see URI list'),
	304: ('Not Modified', 'Document has not changed since given time'),
	400: ('Bad Request','Bad request syntax or unsupported method'),
	# 403: ('Forbidden','Request forbidden -- authorization will not help'),
	# 404: ('Not Found', 'Nothing matches the given URI'),
	405: ('Method Not Allowed', 'Specified method is invalid for this resource.'),
	# 500: ('Internal Server Error', 'Server got itself in trouble'),
	403: ('Forbidden','所请求的文件类型不在服务器允许访问的类型列表中'),
	404: ('Not Found', '服务器中找不到所请求的资源'),
	500: ('Internal Server Error', '服务器内部错误,请报告或求助于你的服务提供者'),
}

class Response_:

	def __init__(self, request_):
		self.request_ = request_

	def write_(self, data_, encoding_='UTF-8'): # 'ISO-8859-1'
		if data_:
			if type(data_) == str:
				data_ = data_.encode(encoding_)
			data_ = memoryview(data_)
			while data_:
				n_ = self.request_.socket_file_.write(data_)
				if n_ is None:
					return False
				data_ = data_[n_:]
			return True
		return False

	def write_first_line_(self, code_):
		reason_ = http_response_codes_.get(code_, ('Unknown reason', ))[0]
		return self.write_("HTTP/1.1 %s %s\r\n" % (code_, reason_))

	def write_header_(self, name_, value_):
		return self.write_("%s: %s\r\n" % (name_, value_))

	def write_content_type_header_(self, content_type_, charset_=None):
		if content_type_:
			ct_ = content_type_ + (("; charset=%s" % charset_) if charset_ else "")
		else:
			ct_ = "application/octet-stream"
		self.write_header_("Content-Type", ct_)

	def write_server_header_(self):
		self.write_header_("Server", "ESP-6288")

	def write_end_header_(self):
		return self.write_("\r\n")

	def write_before_content_(self, code_, headers_, content_type_, charset_, content_length_):
		self.write_first_line_(code_)
		if isinstance(headers_, dict):
			for header_ in headers_:
				self.write_header_(header_, headers_[header_])
		if content_length_ > 0:
			self.write_content_type_header_(content_type_, charset_)
			self.write_header_("Content-Length", content_length_)
		self.write_server_header_()
		self.write_header_("Connection", "close")
		self.write_end_header_()

	def write_response_(self, code_, headers_, content_type_, charset_, content_):
		try:
			if content_:
				if type(content_) == str:
					content_ = content_.encode(charset_)
				content_length_ = len(content_)
			else:
				content_length_ = 0
			self.write_before_content_(code_, headers_, content_type_, charset_, content_length_)
			if content_:
				return self.write_(content_)
			return True
		except:
			try:
				import traceback
				print(traceback.format_exc())
			except:
				pass
			return False

	def write_response_file_(self, filepath_, content_type_=None, headers_=None):
		try:
			size_ = os.stat(filepath_)[6]
			if size_ > 0:
				with open(filepath_, 'rb') as file_:
					self.write_before_content_(200, headers_, content_type_, None, size_)
					try:
						buf_ = bytearray(256)
						while size_ > 0:
							x_ = file_.readinto(buf_)
							if x_ < len(buf_):
								buf_ = memoryview(buf_)[:x_]
							if not self.write_(buf_):
								return False
							size_ -= x_
						return True
					except BrokenPipeError:
						return False
					except Exception as ex_:
						http_handle_ex_(ex_)
						self.write_response_internal_server_error_()
						return False
		except Exception as ex:
			pass
		self.write_response_not_found_()
		return False

	def write_response_OK_(self, headers_=None, content_type_=None, charset_=None, content_=None):
		return self.write_response_(200, headers_, content_type_, charset_, content_)

	def write_response_JSON_OK_(self, json_='{}', headers_=None):
		return self.write_response_(200, headers_, "application/json", "UTF-8", json_)

	def write_response_redirect_(self, location_):
		headers_ = { "Location": location_ }
		return self.write_response_(302, headers_, None, None, None)
	
	def write_response_error_(self, code_, err_msg_=None):
		response_error_tmpl_ = '<h1>%(code)d %(reason)s</h1> %(message)s'
		reason_, msg_ = http_response_codes_.get(code_, ('Unknown reason', ''))
		if err_msg_ is not None:
			msg_ = err_msg_
		err_msg_ = response_error_tmpl_ % {'code': code_, 'reason':reason_, 'message':msg_}
		return self.write_response_(code_, None, "text/html", "UTF-8", err_msg_)

	def write_response_JSON_error_(self, code_, json_='{}'):
		return self.write_response_(code_, None, "application/json", "UTF-8", json_)

	def write_response_not_modified_(self):
		return self.write_response_error_(304)

	def write_response_bad_request_(self):
		return self.write_response_error_(400)

	def write_response_forbidden_(self):
		return self.write_response_error_(403)

	def write_response_not_found_(self):
		return self.write_response_error_(404)

	def write_response_method_not_allowed_(self):
		return self.write_response_error_(405)

	def write_response_internal_server_error_(self, msg_=None):
		return self.write_response_error_(500, msg_)

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2022 / 01/ 30: 新esptool 刷micropython固件指令不是 esptool.py cmd... 而是 esptool cmd... 即可;另外rshell 在 >= python 3.10 的时候出错解决方法可以查看:  已于2022年发布的: 第二章:修复rshell在python3.10出错 免费内容: https://edu.csdn.net/course/detail/29666 micropython语法和python3一样,编写起来非常方便。如果你快速入门单片机玩物联网而且像轻松实现各种功能,那绝力推荐使用micropython。方便易懂易学。 同时如果你懂C语音,也可以用C写好函数并编译进micropython固件里然后进入micropython调用(非必须)。 能通过WIFI联网(2.1章),也能通过sim卡使用2G/3G/4G/5G联网(4.5章)。 为实现语音控制,本教程会教大家使用tensorflow利用神经网络训练自己的语音模型并应用。为实现通过网页控制,本教程会教大家linux(debian10 nginx->uwsgi->python3->postgresql)网站前后台入门。为记录单片机传输过来的数据, 本教程会教大家入门数据库。  本教程会通过通俗易懂的比喻来讲解各种原理与思路,并手把手编写程序来实现各项功能。 本教程micropython本是 2019年6月发布的1.11; 更多内容请看视频列表。  学习这门课程之前你需要至少掌握: 1: python3基础(变量, 循环, 函数, 常用库, 常用方法)。 本视频使用到的零件与淘宝上大致价格:     1: 超声波传感器(3)     2: MAX9814麦克风放大模块(8)     3: DHT22(15)     4: LED(0.1)     5: 8路5V低电平触发继电器(12)     6: HX1838红外接收模块(2)     7:红外发射管(0.1),HX1838红外接收板(1)     other: 电表, 排线, 面包板(2)*2,ESP32(28)  

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值