#python-3.x #rest #flask #pycharm #esp8266
Вопрос:
Я разработал систему проверки пароля с использованием Arduino Nano ESP8266 (интерфейс) и серверной части с сервером API Flask REST.
Ниже приведен мой код ESP8266, который передает запрос HTTP POST на сервер REST API,
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP8266HTTPClient.h>
#include<SoftwareSerial.h>
SoftwareSerial link(4, 0);
byte greenLED = 13;
byte statusLED = 14;
String hexstring = "";
// Replace with your network credentials
const char *ssid = "***********";
const char *password = "***********";
const long utcOffsetInSeconds = 240;
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "asia.pool.ntp.org", utcOffsetInSeconds);
//Week Days
String weekDays[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
//Month names
String months[12] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
Serial.print("Initializing System");
for (int i = 10; i > 0; i--) {
delay(500);
Serial.print(i); Serial.println(' ');
}
pinMode(statusLED, OUTPUT);
// Connect to Wi-Fi
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
link.begin(9600);
link.setTimeout(100);
// clear any pending stuff
link.readString();
pinMode(greenLED, OUTPUT);
}
// Initialize a NTPClient to get time
timeClient.begin();
timeClient.setTimeOffset(19770);
}
void loop() {
timeClient.update();
unsigned long epochTime = timeClient.getEpochTime();
String formattedTime = timeClient.getFormattedTime();
int currentHour = timeClient.getHours();
int currentMinute = timeClient.getMinutes();
int currentSecond = timeClient.getSeconds();
String weekDay = weekDays[timeClient.getDay()];
//Get a time structure
struct tm *ptm = gmtime ((time_t *)amp;epochTime);
int monthDay = ptm->tm_mday;
int currentMonth = ptm->tm_mon 1;
String currentMonthName = months[currentMonth - 1];
int currentYear = ptm->tm_year 1900;
//Print complete date:
String currentDate = String(currentYear) String(currentMonth) String(monthDay) String(currentHour) String(currentMinute) String(currentSecond);
delay(1000);
if (link.available()) {
String rec = link.readString();
Serial.print(F("rec:")); Serial.println(rec);
if (rec.length() > 0) { // print it out
Serial.println(F("Received data"));
for (size_t i = 0; i < rec.length(); i ) {
digitalWrite(greenLED, HIGH); //flash led to show data is arriving
delay(20);
digitalWrite(greenLED, LOW);
if (i % 8 == 0) {
Serial.println();
}
Serial.print(" 0x");
if (rec[i] < 10) {
Serial.print("0");
hexstring = '0';
}
Serial.print(rec[i], HEX);
hexstring = String(rec[i], HEX);
}
Serial.println();
Serial.print("Current Date: ");
Serial.println(currentDate);
Serial.println("Your String Sir:");
Serial.print(hexstring);
Serial.println();
//confirmation();
String sub1 = hexstring.substring(0, 2);
String sub2 = hexstring.substring(16, 32);
String sub3 = hexstring.substring(32, 34);
if (sub3 == "31") { //New User Registartion
String data = "{"user_id" :"" sub1 "","encrypted_password" :"" sub2 "","option" :"" sub3 "" ,"request_datetime" :"" currentDate ""}";
HTTPClient http; //Declare object of class HTTPClient
http.begin("http://192.168.8.228:5000/users/"); //Specify request destination
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(data.c_str());
if (httpCode == 200) {
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
if (payload == "Code1") {
link.read();
Serial.println(F("Prompt other side Confirmation"));
link.print("Success_Code1");
digitalWrite(statusLED, HIGH); //flash led to show data is arriving
delay(20);
digitalWrite(statusLED, LOW);
}
else {
link.read();
Serial.println(F("Prompt other side Error1"));
link.print("Error 1");
}
}
http.end();
rec = ""; // clear for next receive
hexstring = ""; //Clear hexstring
}
else if (sub3 == "32") { //Confirm Password
String data ="{"user_id":"" sub1 "","encrypted_password":"" sub2 "","option":"" sub3 "" ,"request_datetime":"" currentDate ""}";
HTTPClient http; //Declare object of class HTTPClient
String link2 = "http://192.168.8.228:5000/users/" sub1;
http.begin(link2); //Specify request destination
http.addHeader("Content - Type", "application / json");
int httpCode = http.POST(data.c_str());
delay(1000);
Serial.println(data.c_str());
Serial.println(httpCode);
if (httpCode == 200) {
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
if (payload == "Code2") {
link.read();
Serial.println(F("Prompt other side Confirmation"));
link.print("Success_Code1");
digitalWrite(statusLED, HIGH); //flash led to show data is arriving
delay(20);
digitalWrite(statusLED, LOW);
}
}
else {
link.read();
Serial.println(F("Prompt other side Error1"));
link.print("Error 1");
}
http.end();
rec = ""; // clear for next receive
hexstring = ""; //Clear hexstring
}
else if (sub3 == "33") { //Change Password
String data = "{"user_id" :"" sub1 "","encrypted_password" :"" sub2 "","option" :"" sub3 "" ,"request_datetime" :"" currentDate ""}";
HTTPClient http; //Declare object of class HTTPClient
http.begin("http://192.168.8.228:5000/users/"); //Specify request destination
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(data.c_str());
if (httpCode == 200) {
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
if (payload == "Code3") {
link.read();
Serial.println(F("Prompt other side Confirmation"));
link.print("Success_Code1");
digitalWrite(statusLED, HIGH); //flash led to show data is arriving
delay(20);
digitalWrite(statusLED, LOW);
}
}
else {
link.read();
Serial.println(F("Prompt other side Error1"));
link.print("Error 1");
}
http.end();
rec = ""; // clear for next receive
hexstring = ""; //Clear hexstring
}
}
}
}
Как вы можете видеть, существует 3 метода,
Часть нового регистрационного кода пользователя:
if (sub3 == "31") { //New User Registartion
String data = "{"user_id" :"" sub1 "","encrypted_password" :"" sub2 "","option" :"" sub3 "" ,"request_datetime" :"" currentDate ""}";
HTTPClient http; //Declare object of class HTTPClient
http.begin("http://192.168.8.228:5000/users/"); //Specify request destination
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(data.c_str());
if (httpCode == 200) {
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
if (payload == "Code1") {
link.read();
Serial.println(F("Prompt other side Confirmation"));
link.print("Success_Code1");
digitalWrite(statusLED, HIGH); //flash led to show data is arriving
delay(20);
digitalWrite(statusLED, LOW);
}
else {
link.read();
Serial.println(F("Prompt other side Error1"));
link.print("Error 1");
}
}
http.end();
rec = ""; // clear for next receive
hexstring = ""; //Clear hexstring
}
Verify password code part:
else if (sub3 == "32") { //Confirm Password
String data ="{"user_id":"" sub1 "","encrypted_password":"" sub2 "","option":"" sub3 "" ,"request_datetime":"" currentDate ""}";
HTTPClient http; //Declare object of class HTTPClient
String link2 = "http://192.168.8.228:5000/users/" sub1;
http.begin(link2); //Specify request destination
http.addHeader("Content - Type", "application / json");
int httpCode = http.POST(data.c_str());
delay(1000);
Serial.println(data.c_str());
Serial.println(httpCode);
if (httpCode == 200) {
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
if (payload == "Code2") {
link.read();
Serial.println(F("Prompt other side Confirmation"));
link.print("Success_Code1");
digitalWrite(statusLED, HIGH); //flash led to show data is arriving
delay(20);
digitalWrite(statusLED, LOW);
}
}
else {
link.read();
Serial.println(F("Prompt other side Error1"));
link.print("Error 1");
}
http.end();
rec = ""; // clear for next receive
hexstring = ""; //Clear hexstring
}
Below is my Flask/Python API server backend code:
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
import uuid
app = Flask(__name__)
db = SQLAlchemy(app)
DEBUG = True
# app.config['SECRET_KEY'] = 'secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql pymysql://root@localhost:3306/app'
print("App2 Change2")
class User(db.Model):
id = db.Column(db.Integer, primary_key=True, index=True)
user_id = db.Column(db.VARCHAR(10), nullable=False, unique=True)
encrypted_password = db.Column(db.VARCHAR(20), nullable=False)
option = db.Column(db.VARCHAR(3), nullable=False)
request_datetime = db.Column(db.VARCHAR(20), nullable=False)
public_id = db.Column(db.VARCHAR(100), nullable=False)
def __repr__(self):
return f'User <{self.public_id}>'
db.create_all()
@app.route('/')
def home():
return {
'message': 'Welcome to Vinod Test App'
}
@app.route('/users/')
def get_users():
return jsonify([
{
'user_id': user.user_id, 'encrypted_password': user.encrypted_password, 'option': user.option,
'request_datetime': user.request_datetime
} for user in User.query.all()
])
@app.route('/users/<user_id>/')
def get_user(user_id):
print(user_id)
user = User.query.filter_by(user_id=user_id).first_or_404()
return {
'user_id': user.user_id, 'encrypted_password': user.encrypted_password,
'public_id': user.public_id, 'original_time': user.request_datetime
}
# Add New User
@app.route('/users/', methods=['POST'])
def create_user():
data = request.get_json()
print(request.get_json())
if not 'user_id' in data or not 'encrypted_password' in data or not 'option' in data:
return jsonify({
'error': 'Bad Request',
'message': 'User Id and Encrypted Data is Missing'
}), 400
if len(data['encrypted_password']) < 16:
return jsonify({
'error': 'Bad Request',
'message': 'Length Error in Encrypted Data'
}), 400
u = User(
user_id=data['user_id'],
encrypted_password=data['encrypted_password'],
option=data.get('option'),
request_datetime=data['request_datetime'],
public_id=str(uuid.uuid4())
)
db.session.add(u)
db.session.commit()
return {
'id': u.user_id, 'encrypted_data': u.encrypted_password,
'public_id': u.public_id, 'original_time': u.request_datetime,
}, 200
# Verify Password
@app.route('/users/<user_id>', methods=['POST'])
def check_user(user_id):
data = request.get_json()
if 'user_id' not in data:
return {
'error': 'Bad Request',
'message': 'User_id field needs to be present'
}, 400
user = User.query.filter_by(user_id=user_id).first_or_404()
user.user_id = data['user_id']
if 'user_id' in data:
if user.encrypted_password == data['encrypted_password']:
return jsonify({
'user_id': user.public_id,
'encrypted_password': user.encrypted_password,
'original_time': user.request_datetime
})
else:
return {
'error': 'Bad Request',
'message': 'Password Do Not Match'
}, 400
@app.route('/users/<user_id>/', methods=['DELETE'])
def delete_user(user_id):
user = User.query.filter_by(user_id=user_id).first_or_404()
db.session.delete(user)
db.session.commit()
return {
'success': 'Data deleted successfully'
}
if __name__ == '__main__':
app.run(debug=True)
Моя проблема в том, что он не работает, когда проверка пароля передается через ESP8266 на серверную часть для проверки пароля. Но регистрация нового пользователя работает при прохождении через ESP8266.
Ниже приведена ошибка, которую я получаю в PyCharm:
* Running on http://192.168.8.100:5000/ (Press CTRL C to quit)
[2021-09-26 14:57:55,237] ERROR in app: Exception on /users/32 [POST]
Traceback (most recent call last):
File "C:UsersVinod AmarathungaPycharmProjectTest1server1venvlibsite-packagesflaskapp.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "C:UsersVinod AmarathungaPycharmProjectTest1server1venvlibsite-packagesflaskapp.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:UsersVinod AmarathungaPycharmProjectTest1server1venvlibsite-packagesflaskapp.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "C:UsersVinod AmarathungaPycharmProjectTest1server1venvlibsite-packagesflaskapp.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "C:UsersVinod AmarathungaPycharmProjectTest1server1app2_Change2.py", line 108, in check_user
if 'user_id' not in data:
TypeError: argument of type 'NoneType' is not iterable
192.168.8.174 - - [26/Sep/2021 15:52:20] "POST /users/32 HTTP/1.1" 500 -
Но когда я отправляю тот же запрос (Проверить пароль), Postman
он работает,
ниже приведен ответ почтальона на проверку:
Этот запрос был таким же, отправленным с ESP8266, который был захвачен с тестового сервера Mockon:
Ожидаемый ответ бэкенда [Работа с почтальоном]
192.168.8.103 - - [26/Sep/2021 15:52:59] "POST /users/32 HTTP/1.1" 400 -
Примечание: Зашифрованные данные вместе с пользовательскими вводами передаются в ESP с помощью Arduino Nano, как показано ниже:
Ответ №1:
Ошибка TypeError: argument of type 'NoneType' is not iterable
означает, что ваш data = request.get_json()
возврат a None
. Причину, по которой он возвращает a None
, можно найти в документации API falsk.Request.get_json. Там было написано:
По умолчанию эта функция не вернет ничего, если тип mimetype не является приложением/json
Взгляните на свой код Arduino, вы добавляете дополнительные пробелы в http-заголовке:
http.addHeader("Content - Type", "application / json");
Заголовок HTTP должен быть:
Content-Type: application/json