I have developed a password verification system using Arduino Nano ESP8266 (FrontEnd) and Backend with Flask REST API server.
Following is my code of ESP8266, Which is passing the HTTP POST request to REST API server,
#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 *)&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
}
}
}
}
As you can see, There are 3 methods,
New user registration code part:
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)
My issue is: It is not working when verify password passed through the ESP8266 to the Backend for verify password. But new user registration works when passed through ESP8266.
Below is the error I am getting in the 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:\Users\Vinod Amarathunga\PycharmProject\Test1\server1\venv\lib\site-packages\flask\app.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\Vinod Amarathunga\PycharmProject\Test1\server1\venv\lib\site-packages\flask\app.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\Vinod Amarathunga\PycharmProject\Test1\server1\venv\lib\site-packages\flask\app.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\Vinod Amarathunga\PycharmProject\Test1\server1\venv\lib\site-packages\flask\app.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "C:\Users\Vinod Amarathunga\PycharmProject\Test1\server1\app2_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 -
But when I send the same request (Verify Password) from Postman
it works,
Below is the Postman response on verification:
This request was the same sent from ESP8266 which was captured from Mockon test server:
Backend expected response [Working with Postman]
192.168.8.103 - - [26/Sep/2021 15:52:59] "POST /users/32 HTTP/1.1" 400 -
Note: Encrypted data along with user inputs are passed to ESP by an Arduino Nano as below:
CodePudding user response:
The error TypeError: argument of type 'NoneType' is not iterable
means that your data = request.get_json()
return a None
. The reason why it return a None
can be found in falsk.Request.get_json API documentation. It said:
By default this function will return None if the mimetype is not application/json
Take a look at your Arduino code, you add extra spaces on the http header:
http.addHeader("Content - Type", "application / json");
The HTTP header should be:
Content-Type: application/json