WEEK 14 - INTERFACE AND APPLICATION PROGRAMMING

this week i want to explore as many messaging protocols. .

hero shot

assignment

individual assignment

web serial api

The Web Serial API is one of a set of APIs that allow websites to communicate with peripherals connected to a user's computer. It provides the ability to connect to devices that are required by the operating system to communicate via the serial API, rather than USB which can be accessed via the WebUSB API, or input devices that can be accessed via WebHID API.

image-7.jpg

from icircuit

    <!-- Heading -->
    <h2 id="heading">WebSerial API for Week 14</h2>

    <!-- Toggle switch for controlling LED -->
    <label class="toggle-switch">
        <input type="checkbox" onchange="toggleColor()">
        <span class="slider"></span>
    </label>

    <!-- Connect button -->
    <button class="connect-button" onclick="connectDevice()">Connect</button>

  • It contains a toggle switch (<input type="checkbox">) wrapped in a <label> element. This switch is intended to control an LED.
<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>web serial</title>

<style>

/* Styling for the toggle switch */

.toggle-switch {

position: relative;

display: inline-block;

width: 50px;

height: 26px;

}

  

.toggle-switch input {

opacity: 0;

width: 0;

height: 0;

}

  

.slider {

position: absolute;

cursor: pointer;

top: 0;

left: 0;

right: 0;

bottom: 0;

background-color: #ccc;

border-radius: 26px; /* Round shape */

-webkit-transition: .4s;

transition: .4s;

}

  

.slider:before {

position: absolute;

content: "";

height: 22px;

width: 22px;

left: 2px;

bottom: 2px;

background-color: white;

border-radius: 50%; /* Round shape */

-webkit-transition: .4s;

transition: .4s;

}

  

input:checked + .slider {

background-color: #e3dd1f; /* Red color when toggle is on */

}

  

input:focus + .slider {

box-shadow: 0 0 1px #2196F3;

}

  

input:checked + .slider:before {

-webkit-transform: translateX(22px);

-ms-transform: translateX(22px);

transform: translateX(22px);

}

  

/* Styling for the connect button */

.connect-button {

padding: 10px 20px;

background-color: #4CAF50;

border: none;

color: white;

text-align: center;

text-decoration: none;

display: inline-block;

font-size: 16px;

margin-left: 20px;

border-radius: 5px;

cursor: pointer;

}

</style>

</head>

<body>

  

<h2 id="heading">WebSerial API for Week 14</h2>

  

<label class="toggle-switch">

<input type="checkbox" onchange="toggleColor()">

<span class="slider"></span>

</label>

  

<button class="connect-button" onclick="connectDevice()">Connect</button>

  

<script>

let port;

let isToggled = false;

// Function to handle the connect button click event

async function connectDevice() {

try {

// Request access to the serial port

port = await navigator.serial.requestPort();

// Set the baud rate to 9600

await port.open({ baudRate: 9600 });

// Log a success message

console.log('Port opened successfully with baud rate 9600.');

// Change the text of the connect button to "Connected"

document.querySelector('.connect-button').innerText = "Connected";

// Add a disconnect event listener

port.addEventListener('disconnect', handleDisconnect);

} catch (error) {

// Log any errors

console.error('Error:', error);

// Change the text of the connect button back to "Connect"

document.querySelector('.connect-button').innerText = "Connect";

}

}

  

// Function to handle disconnect event

function handleDisconnect() {

console.log('Device disconnected.');

// Change the text of the connect button back to "Connect"

document.querySelector('.connect-button').innerText = "Connect";

}

  

// Function to handle toggle switch state change

function toggleColor() {

// If the toggle switch is turned on

if (document.querySelector('.toggle-switch input').checked) {

// Send command to keep LED on

sendToSerial();

} else {

// Send command to turn off LED

sendToSerial();

}

}

  

// Function to send data to the serial port

async function sendToSerial() {

// Obtain a writable stream writer for the serial port

const writer = port.writable.getWriter();

const encoder = new TextEncoder()

  

// Define the data to send based on the toggle state

const dataToSend = isToggled ? '0' : '1';

  

// Toggle the state for the next iteration

isToggled = !isToggled;

  

// Write the data to the serial port

writer.write(encoder.encode(dataToSend)).then(() => {

// Log a message when the data is successfully sent

console.log("Sent: " + dataToSend);

});

  

// Release the lock on the writer after writing data

writer.releaseLock();

  
  

}

</script>

  

</body>

</html>

  
  

<!-- <!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Serial</title>

<style>

.navbar {

display: flex;

position: absolute;

padding: 1.5rem 1.5rem;

font-size: 2rem;

font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;

}

  

.navbar span {

font-weight: 700;

}

  

.container {

width: 100vw;

height: 100vh;

}

.container .buttons {

display: flex;

align-items: center;

justify-content: center;

flex-direction: column;

gap: 1rem;

width: 100%;

height: 100%;

}

.container .buttons button{

font-size: 2rem;

font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;

padding: 1rem 2rem;

border-radius: 1rem;

background-color: #e9e9e9;

border: 1px solid #cccccc;

cursor: pointer;

box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -2px, rgba(0, 0, 0, 0.3) 0px 3px 7px -3px;

transition: 0.5s all;

}

.container .buttons button:hover{

box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px;

}

</style>

</head>

<body>

<nav class="navbar">WebSerial <span> API</span></nav>

  

<div class="container">

<div class="buttons">

<div class="textarea">

<textarea name="textarea" id="serial" cols="40" rows="10"></textarea>

</div>

<div>

<button id="connect">Connect</button>

<button id="toggle">On/Off</button>

</div>

</div>

</div>

  

<script>

let port;

let isToggled = false;

let receivedText = '';

document.getElementById('connect').addEventListener('click', async () => {

port = await navigator.serial.requestPort();

await port.open({ baudRate: 9600 });

const reader = port.readable.getReader();

const processMsg = async () => {

const decoder = new TextDecoder();

const { value, done } = await reader.read();

if (!done) {

receivedText += decoder.decode(value);

document.getElementById('serial').value = receivedText;

processMsg();

} else {

reader.releaseLock();

}

}

processMsg();

});

<textarea name="textarea" id="serial" cols="30" rows="10"></textarea>

document.getElementById('toggle').addEventListener('click', async () => {

const encoder = new TextEncoder()

const writer = port.writable.getWriter();

const dataToSend = isToggled ? '1' : '0';

isToggled = !isToggled;

writer.write(encoder.encode(dataToSend)).then(() => {

console.log("Sent: " + dataToSend);

});

writer.releaseLock();

});

</script>

</body>

</html> -->

from chat gpt

i uploaded a arduino code to serial read "1 "& "0" a.

me testing the code

Screenshot 2024-05-02 at 9.55.21 PM.jpg

screenshot

web socket api

The WebSocket API is an advanced technology that makes it possible to open a two-way interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.

WebSocket-Connection.jpg

const WebSocket = require('ws');

  

const wss = new WebSocket.Server({ port: 8080 });

  

const clients = [];

  

wss.on('connection', function connection(ws) {

clients.push(ws);

  

ws.on('message', function incoming(message) {

// Broadcast the received message to all clients except the sender

clients.forEach(client => {

if (client !== ws && client.readyState === WebSocket.OPEN) {

client.send(message);

}

});

});

  

ws.on('close', function() {

// Remove the closed WebSocket connection from the clients array

clients.splice(clients.indexOf(ws), 1);

});

});

code for server.js from chat gpt

to make websocket work we need to run a server

first we have to run the server and then open the html.

    <script>
        // WebSocket connection establishment
        const ws = new WebSocket('ws://192.168.33.22:8080');

        // Event handler for successful connection
        ws.onopen = function() {
            console.log('Connected.');
        };

        // Event handler for receiving messages
        ws.onmessage = function(event) {
            // Message handling logic
        };

        // Function for sending messages
        function sendMessage() {
            // Message sending logic
        }

        // Function for displaying messages in the message container
        function displayMessage(message) {
            // Message display logic
        }
    </script>

from chat gpt

in the above code

  • The JavaScript code establishes a WebSocket connection to the server at ws://192.168.33.22:8080.
  • The onopen event handler logs a message when the connection is successfully established.
  • The onmessage event handler processes incoming messages from the WebSocket server. It distinguishes between text messages and Blob (binary data) messages and logs them accordingly.
  • The sendMessage() function retrieves the message from the input field, sends it to the server via the WebSocket connection, and clears the input field.
  • The displayMessage() function is defined but not used in this snippet. It's meant to display messages received from the server in the messageContainer.

communicating using external device and receiving it on server.

websocket allow us for cross device communciation.

when i am messaging with phone there was an issue of blob. i solved it using the below code snippet.

ws.onmessage = function(event) {

if (typeof event.data === 'string') {

// Handle text message

console.log('Received:', event.data);

} else if (event.data instanceof Blob) {

// Convert Blob to text

const reader = new FileReader();

reader.onload = function() {

console.log('Received:', reader.result);

};

reader.readAsText(event.data);

}

};

code to convert blob to text

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>WebSocket Client</title>

</head>

<body>

<div id="messageContainer"></div> <!-- Container for displaying messages -->

<input type="text" id="messageInput" placeholder="Type your message">

<button onclick="sendMessage()">Send Message</button>

  

<script>

const ws = new WebSocket('ws://192.168.33.22:8080');

  

ws.onopen = function() {

console.log('Connected.');

};

  

ws.onmessage = function(event) {

if (typeof event.data === 'string') {

// Handle text message

console.log('Received:', event.data);

} else if (event.data instanceof Blob) {

// Convert Blob to text

const reader = new FileReader();

reader.onload = function() {

console.log('Received:', reader.result);

};

reader.readAsText(event.data);

}

};

  
  

function sendMessage() {

const messageInput = document.getElementById('messageInput');

const message = messageInput.value;

console.log('Sent:', message); // Log the message before sending

ws.send(message);

messageInput.value = ''; // Clear the input field after sending

}

  

function displayMessage(message) {

const messageContainer = document.getElementById('messageContainer');

// Create a new <p> element to display the message

const messageElement = document.createElement('p');

messageElement.textContent = message;

// Append the message element to the message container

messageContainer.appendChild(messageElement);

}

</script>

</body>

</html>

code fro cleint.js - from chat gpt

Screenshot 2024-05-04 at 4.02.16 AM.jpg

making a spin wheel interface with WEEK 11 - INPUT DEVICES board

i am going to create the interface with my hall effect board in WEEK 11 - INPUT DEVICES using web serail api .lets use chat gpt tool make it happen.

IMG_7600.jpg

PHOTO-2024-06-26-23-40-54.jpg
circuit diagram of the setup.

i first prompted in chat gpt

create a web serial api interface to show count of this Arduino code using html

i inputed this arduino code to count magnet as reference.







// Define the pin for the hall effect sensor

const int hallEffectPin = 31;

  

// Variable to store the count of magnet detections

int magnetCount = 0;

  

// Flag to track whether the sensor was already triggered

bool sensorTriggered = false;

  

void setup() {

// Initialize serial communication

Serial.begin(9600);

  

// Set the hall effect sensor pin as input

pinMode(hallEffectPin, INPUT);

}

  

void loop() {

// Read the state of the hall effect sensor

int sensorState = digitalRead(hallEffectPin);

  

// If the sensor detects a magnet (LOW state) and it wasn't triggered before

if (sensorState == LOW && !sensorTriggered) {

// Increment the magnet count

magnetCount++;

  

// Print the current magnet count

Serial.print("Magnet detected! Count: ");

Serial.println(magnetCount);

  

// Set the sensor triggered flag to true

sensorTriggered = true;

}

// If the sensor is not detecting a magnet (HIGH state)

// reset the sensor triggered flag to false

if (sensorState == HIGH) {

sensorTriggered = false;

}

  

// // A short delay to prevent rapid counting due to sensor noise

// delay(100);

}




  • Initial Arduino Setup:

  • Developed Arduino code to count magnet detections using a hall effect sensor and transmit count data over serial communication.

  • HTML and CSS Setup for Web Serial Interface:

  • Created an HTML template with CSS styling for a web serial interface, featuring a toggle switch and a connect button.

  • JavaScript for Serial Communication:

  • Implemented JavaScript to establish and manage serial communication with the Arduino, facilitating data exchange.

  • Display Setup and Interaction:

  • Designed the web interface to display real-time magnet count and support user actions such as connecting to the Arduino and resetting the count.

  • Enhancements and Additional Features:

  • Integrated additional messages to display various outcomes, enhancing user interaction and system functionality.

here i summarised the whole prompt session into a single one.

Create a web interface that connects to an Arduino via Web Serial. The Arduino code uses a hall effect sensor to detect magnets and sends predefined messages over serial communication. These messages include "$10", "100$", "JACKPOT", "0", "TRY AGAIN", and "250$". Implement a reset functionality so that when a reset button on the web page is clicked, the Arduino resets its message index and sends the message "LET'S START". Ensure the web interface displays these messages in real-time and updates accordingly when a new message is received or after a reset.

inorder to implemen web serial api there are two process. firstly, we need to burn a set of code into arduino for serial reading and other for html and javascript in computer which you can open in any browser.

  • Arduino Code: Handles sensor input, cycles through predefined messages, and communicates with the computer via serial.
  • HTML/JavaScript Code: Provides a user interface for connecting to the Arduino via Web Serial API, displaying status and messages received from the Arduino, and allowing the user to reset the message index.

arduino code explanation

The Arduino code is responsible for handling the hall effect sensor input and serial communication with the connected computer (or device running a browser).

// Define the pin for the hall effect sensor
const int hallEffectPin = 31;

// Array of messages
const char* messages[] = {"$10", "100$", "JACKPOT", "0", "TRY AGAIN", "250$"};
const int numMessages = 6;

// Variable to store the current message index
int messageIndex = 0;

// Flag to track whether the sensor was already triggered
bool sensorTriggered = false;

void setup() {
  // Initialize serial communication
  Serial.begin(9600);

  // Set the hall effect sensor pin as input
  pinMode(hallEffectPin, INPUT);
}

void loop() {
  // Check if data is available on the serial port
  if (Serial.available()) {
    char incomingByte = Serial.read();
    // If a 'R' is received, reset the message index and print "LET'S START"
    if (incomingByte == 'R') {
      messageIndex = 0;
      Serial.println("LET'S START");
    }
  }

  // Read the state of the hall effect sensor
  int sensorState = digitalRead(hallEffectPin);

  // If the sensor detects a magnet (LOW state) and it wasn't triggered before
  if (sensorState == LOW && !sensorTriggered) {
    // Increment the message index
    messageIndex++;
    if (messageIndex >= numMessages) {
      messageIndex = 0;
    }

    // Print the current message
    Serial.println(messages[messageIndex]);

    // Set the sensor triggered flag to true
    sensorTriggered = true;
  }
  // If the sensor is not detecting a magnet (HIGH state), reset the sensor triggered flag to false
  if (sensorState == HIGH) {
    sensorTriggered = false;
  }

  // A short delay to prevent rapid counting due to sensor noise
  delay(100);
}

Explanation:

  • hallEffectPin: Defines the Arduino pin connected to the hall effect sensor, which detects magnetic field changes.
  • messages[]: An array of messages that can be cycled through when a magnet is detected.
  • messageIndex: Tracks the current index in the messages array.
  • sensorTriggered: Flag to prevent rapid counting when the sensor detects a magnet.

Setup Function:

  • Initializes serial communication with a baud rate of 9600.
  • Configures hallEffectPin as an input pin.

Loop Function:

  • Serial Communication:

    • Checks for incoming data on the serial port (Serial.available() and Serial.read()).
    • If 'R' is received, resets messageIndex to 0 and sends "LET'S START" over serial.
  • Sensor Reading:

    • Reads the state of hallEffectPin (digitalRead(hallEffectPin)).
    • If the sensor detects a magnet (LOW state) and sensorTriggered is false, increments messageIndex to cycle through messages.
    • Prints the current message to the serial port (Serial.println(messages[messageIndex])).
    • Sets sensorTriggered to true to prevent rapid counting.
  • Delay:

    • Adds a short delay (delay(100)) to prevent rapid multiple counts due to sensor noise.

HTML and JavaScript Code Explanation

The HTML and JavaScript code provides a user interface to connect to the Arduino via Web Serial API and display messages received from the Arduino.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Magnet Detection Counter</title>
    <style>
        body {
            margin: 0;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: black;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 3em;
            text-align: center;
        }
        
        .connect-button, .reset-button {
            position: absolute;
            top: 20px;
            padding: 10px 20px;
            background-color: #4CAF50;
            border: none;
            color: white;
            text-align: center;
            text-decoration: none;
            font-size: 16px;
            border-radius: 5px;
            cursor: pointer;
        }

        .connect-button {
            right: 20px;
        }

        .reset-button {
            right: 150px;
        }

        .connect-button:disabled, .reset-button:disabled {
            background-color: #888;
            cursor: not-allowed;
        }

        #status {
            position: absolute;
            top: 20px;
            left: 20px;
            font-size: 0.5em;
        }
    </style>
</head>
<body>
    <button id="connect" class="connect-button">Connect to Arduino</button>
    <button id="reset" class="reset-button">Reset Counter</button>
    <p id="status">Status: Not Connected</p>
    <div id="count">LET'S START</div>

    <script>
        const connectButton = document.getElementById('connect');
        const resetButton = document.getElementById('reset');
        const statusDisplay = document.getElementById('status');
        const countDisplay = document.getElementById('count');

        let port;
        let reader;

        async function connect() {
            try {
                // Request a port and open a connection
                port = await navigator.serial.requestPort();
                await port.open({ baudRate: 9600 }); // Set baud rate here
                statusDisplay.textContent = 'Status: Connected';

                // Disable the connect button to prevent multiple connections
                connectButton.disabled = true;
                connectButton.textContent = 'Connected';

                reader = port.readable.getReader();
                readLoop();
            } catch (error) {
                console.error('Error:', error);
                statusDisplay.textContent = 'Status: Error connecting to Arduino';
            }
        }

        async function readLoop() {
            while (true) {
                try {
                    const { value, done } = await reader.read();
                    if (done) {
                        // Allow the serial port to be closed later
                        reader.releaseLock();
                        break;
                    }
                    // Parse the incoming data and update the display
                    const text = new TextDecoder().decode(value).trim();
                    if (text) {
                        countDisplay.textContent = text;
                    }
                } catch (error) {
                    console.error('Read error:', error);
                    break;
                }
            }
        }

        async function resetCounter() {
            if (port) {
                try {
                    const writer = port.writable.getWriter();
                    const encoder = new TextEncoder();
                    await writer.write(encoder.encode('R'));
                    writer.releaseLock();
                    countDisplay.textContent = "LET'S START";
                } catch (error) {
                    console.error('Error:', error);
                }
            }
        }

        connectButton.addEventListener('click', connect);
        resetButton.addEventListener('click', resetCounter);
    </script>
</body>
</html>

Explanation:

  • HTML Structure:

    • Contains buttons (#connect and #reset) for connecting to the Arduino and resetting the counter.
    • Displays status (#status) and current message (#count) received from the Arduino.
  • CSS Styling:

    • Styles the body with black background, white text, and centers the content.
    • Positions buttons and status text.
  • JavaScript Functionality:

    • Event Listeners:
      • connectButton.addEventListener('click', connect); triggers connect() to initiate a connection to the Arduino via Web Serial API.
      • resetButton.addEventListener('click', resetCounter); triggers resetCounter() to send a reset command ('R') to the Arduino and updates the display with "LET'S START".
  • Functions:

    • connect(): Requests access to the serial port, opens a connection with specified baud rate (9600), updates status display, and starts reading data from the Arduino.

    • read Loop(): Continuously reads data from the Arduino serial port. When data is received, decodes it, trims any extra whitespace, and updates countDisplay with the received message.

    • RESET-COUNTER(): Checks if a port is open, creates a writer to the serial port, sends a 'R' character to the Arduino to reset the message index, updates countDisplay with "LET'S START".

Together, these codes create a system where a hall effect sensor triggers messages on the Arduino, which are then displayed in real-time on a web page using Web Serial API.

Screenshot 2024-06-26 at 10.52.40 PM.jpg
interface

the result

demo

reflection

Today, this project has boosted my confidence that I can create any application with proper prompting and understanding.