DEVICE INTERFACE - SERVER - RESPONSIVE DOM ELEMENTS WITH INPUT FORM

This week I want to build a chat app with human interface device embedded. The only device I could get is my Arduino and a force sensor. So I tried with them to build a chat application which also has dynamics with the force we used to type on the keyboard. Because sometimes the force of typing can be a representation of the users' emotional status.

The first step is to build the connection from arduino to server, to get the force data with out serial port. With the code below, we can send data use Http protocol via WiFi.

#include <WiFiNINA.h>
#include <ArduinoHttpClient.h>
#include "config.h"

int fsrAnalogPin = 0; 

//wifi connection
WiFiClient wifi;
HttpClient client = HttpClient(wifi, SERVER_ADDRESS, SERVER_PORT);

int wifi_status = WL_IDLE_STATUS;
 
void setup(void) {
  Serial.begin(9600);   // We'll send debugging information via the Serial monitor
  pinMode(LEDpin, OUTPUT);

  connectWiFi();
}
 
void loop(void) {

  int fsrReading;      // the analog reading from the FSR resistor divider
  int output;
  
  fsrReading = analogRead(fsrAnalogPin);

  output = map(fsrReading, 0, 1023, 0, 255);

  Serial.print("reading = ");
  Serial.println(output);

  Serial.println("Sending data to server via HTTP POST");
  String contentType = "application/x-www-form-urlencoded";
  String postData = "reading= " + String(output);

  client.post("/inputdata", contentType, postData);

  Serial.println("postdata:"+postData);

    // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);

  Serial.println("Waiting for two seconds\\n");

  
}

void connectWiFi() {

  Serial.print("WiFi firmware version ");
  Serial.println(WiFi.firmwareVersion());
 
  // attempt to connect to WiFi network
  while (wifi_status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(WIFI_SSID);
    wifi_status = WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

    // wait 3 seconds for connection
    delay(3000);
  }
  Serial.println("Connected to WiFi");
  printWiFiStatus();

  delay(2000);

}

void printWiFiStatus() {
  // print your WiFi IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
}

If we use curl to represent how the request from arduino would be like, I think it equals the commands below.

curl --header "Content-Type: application/x-www-form-urlencoded" \\
 --request POST \\
 --data 'reading=100' \\
 <http://192.168.8.102:3000/inputdata>

With the server below, I got few outputs to debug with.

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var reqBody;
var fontSize;

var urlencodedBodyParser = bodyParser.urlencoded({ extended: true });
app.use(urlencodedBodyParser);
app.use(bodyParser.json());

app.use(express.static("public"));

var datas = [];

const port = 3000;
const server = app.listen(port);
console.log("Server is running on port" + port);

const io = require("socket.io")().listen(server);

io.sockets.on('connection', function (socket) {
  console.log("We have a new client: " + socket.id);
});

app.get('/', function (req, res) {
  res.send('say something here!');
});

app.post('/inputdata', function (req, res) {

  console.log("req:"+req.body);
  reqBody=req.body.reading;
  var dataToSave = {
    text: req.body.data,
    color: req.body.color,
  };
  
  // if(req.body.reading!=null){
  //   fontsize=parseInt(req.body.reading/4);
  // }
  // else{
  //   fontsize=24;
  // }
  let readingValue=Number(req.body.reading);
  fontsize=parseInt(req.body.reading/4);
  console.log(fontSize);

  let dt = new Date();
  dataToSave.timestamp = dt.getTime();
  let remoteAddress = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  dataToSave.remoteAddress = remoteAddress;

  datas.push(dataToSave);

  //send with raw dom
  var output = `<h4>Submitted Data until+${dt}</h4>`;

  for (var i = 0; i < datas.length; i++) {
    // res.send('color:'+ datas[i].color+'text:'+ datas[i].text+'/n');
    output += "<div style='color: " + datas[i].color + "''white-space:pre' 'font-size:"+ fontSize +"px'>"+ datas[i].text;
    output +=`    from+${remoteAddress}+</div>`;
  }

  console.log("output:" + output);
  io.sockets.emit('update', output);

  res.send(reqBody);
  //send json

  /////send html
  // var output = "<html><body>";
  // output += "<h1>Submitted Data</h1>";

  // for(var i=0;i<datas.length;i++){
  //   // res.send('color:'+ datas[i].color+'text:'+ datas[i].text+'/n');
  //   output += "<div style='color: " + datas[i].color + "'>" + datas[i].text + "</div>";
  //   }

  // output += "</body></html>";

  /////send without html
  // var output = "<h2>Submitted Data</h2>";

  // for(var i=0;i<datas.length;i++){
  //   // res.send('color:'+ datas[i].color+'text:'+ datas[i].text+'/n');
  //   output += "<div style='color: " + datas[i].color + "'>" + datas[i].text + "</div>";
  //   }

  // console.log(output);
  // res.send(output);

});

I want to see the request.body so I made it as the response . Here we could see it has been already parse to json.

Then I change the response to request.body.reading, and I could get a value.

When I came here I am still not sure if it's okay that the request body is {"reading":"100"}. It's a key-value pare but I wonder if the value I got is string because it has "" around. So I used Number() and parseInt() function to deal with the value in request.

I made font size as a global variable and give it value by "fontsize=parseInt(req.body.reading/4);", and send DOM element with web socket in my post route. Here is what the socket clients would receive.

output:<h4>Submitted Data until+Sat Feb 20 2021 00:52:58 GMT+0800 (China Standard Time)</h4>
<div style='color: undefined''white-space:pre' 'font-size:undefinedpx'>undefined    from+::ffff:192.168.8.102+</div>

And the browser client would post text and color data. All the chat messages would be displayed in the result div.

<html>
    <head>
        <title>T</title>
        <script src="<https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.1/socket.io.js>" integrity="sha512-oFOCo2/3DtjrJG4N27BjSLQWoiBv171sK6a+JiWjp/7agxC2nCUP358AqzxkBUb5jX8g6CYLPdSKQTbC0weCwA==" crossorigin="anonymous"></script>
        <!-- <script src="js/socket.io.js"></script> -->
        <script type="text/javascript">
          var socket=io.connect();
          socket.on('connect',function(){
              console.log("connected!");
          });

          socket.on('update',function(data){
            //   let parsedData=JSON.parse(data);
              
              document.getElementById('result').innerHTML=data;
              console.log(data);
          });
        </script>
    </head>
    <body>
        <form id="input" method="POST" action="/inputdata">
            <label for="data">Enter Text to Post:</label>
            <input type="text" name="data" value="say something">
            <input type="color" name="color">
            <input type="submit" name="submit" value="Submit">
        </form>
        <div id='result'></div>
    </body>

</html>

Here are several problems I need to fix. The force value to change the DOM element is always undefined.

The two side of this problem: one is the type of this variable and its scope might have something wrong. The other is, the input data from force sensor connected to Arduino device and the text&color data from browser client is not always sync. I tried to solve this question by adding "if(req.body.reading!=null{fontsize=parseInt(req.body.reading/4)} else{fontsize=24 }"