Skip to main content
Digital Frontiers Report

SHIFT DIGITAL FRONTIERS REPORT UNVEILED DURING LONDON DATA WEEK

By Writing No Comments

SHIFT, in collaboration with Arup and the Centre for Advanced Spatial Analysis, Connected Environments Group at University College London (UCL), have released  the “SHIFT Digital Frontiers” report, a visionary roadmap outlining the transformative use of London’s physical and data assets within Queen Elizabeth Olympic Park to drive innovation and act as London’s testbed for addressing pressing urban challenges. The report’s release coincides with London Data Week, underscoring the critical role of data, notably real-time data, in shaping the city’s sustainable future.

The London 2012 Olympic and Paralympic Games sparked a renaissance in east London’s tech and innovation sector. Building on this legacy, the SHIFT digital ecosystem emerges as the next wave of east London’s evolution, aiming to transform the Park into a pioneering digital R&D hub.

The SHIFT Digital Frontiers report is the product of a dynamic collaboration between SHIFT, Arup’s Foresight and Technical Services Teams, and the Connected Environments Lab at the UCL Bartlett Centre for Advanced Spatial Analysis. The report outlines the background and future development roadmap of a real-time data ecosystem to act as a testbed for the city’s big issues.

The partnership has crafted a strategic vision advocating for an ambitious digital innovation ecosystem made up of startups, universities, large corporations and local authorities. Users of the Digital Frontiers platform will contribute hyper-local data and in turn enable testing and showcasing of new technologies. This ecosystem leverages data, technology infrastructure, and robust stakeholder engagement to address the climate emergency, urban health, and urban mobility.

The report articulates the strategic vision through three strategic themes: digital integration, inclusivity and environment. It also details nine essential technology requirements to ensure the digital platform’s scalability, reliability, and security, focusing on interoperable, real-time, and spatial data. Demonstrating end-to-end data journeys within the Park and beyond, a set of case studies highlights market differentiators and best practices, showcasing the potential for local and global impact. Finally, a comprehensive set of recommendations and actionable steps towards establishing governance models, addressing immediate challenges, and achieving quick wins are presented.

SHIFT Digital Frontiers aims to amplify east London’s data capabilities, acting as a digital testbed to create a template for city-wide adoption in London and beyond. By integrating three-dimensional assets with cutting-edge research hardware, the initiative sets a pioneering path for businesses to develop, test, and refine innovative solutions.

Beyond technical innovation, the SHIFT Digital Frontiers vision seeks to empower policymakers with live, actionable data, informing strategic decision-making within the UK government and beyond. It represents a transformative step towards a more informed, responsive, and dynamic governance model.

Abdul Rahim, SHIFT’s Chief Innovation Officer, said: 

“We are excited to unveil the SHIFT Digital Frontiers report during London Data Week. This initiative marks a significant step in transforming the Park into a leading digital ecosystem that not only addresses climate challenges but also fosters urban health and mobility. Our collaboration with Arup and UCL has been instrumental in shaping a vision that leverages data and technology to create tangible, sustainable solutions for our communities.” – Abdul Rahim, Chief Innovation Officer, SHIFT.

The SHIFT Digital Frontiers report can be downloaded here

Literacy Clock using MQTT

Turn Any Device into a Literary Clock with our MQTT Feed

By Making No Comments

The Concept of the Literary Clock

A literary clock is a unique fusion of literature and timekeeping. Every minute of the day is represented by a corresponding quote from a literary work, providing not just the time, but a nugget of wisdom, humor, or beauty from the world of books. This idea transforms the mundane act of checking the time into a delightful literary experience. The initial concept, as outlined by the original Literary Clock Project, involves creating a clock that displays quotes from various literary works for every minute of the day. This concept not only appeals to book lovers but also serves as an artistic and educational piece, bringing literature into everyday life in a novel way. For example, as we type this the time is twenty one minutes to five and the quote from the database, including the book name is:

 

“I was told that in his vest pocket he kept a chronometer instead of a watch. If someone asked him what time it was, he would say, “”A minute and twenty-one seconds to five.””” Book: The Collected Stories

Crowdsourcing the Literary Database

An essential aspect of this project was the crowdsourcing of the literary database. The Literary Clock Project engaged a global community of literature enthusiasts to contribute quotes for every minute of the day. This collaborative effort created a diverse and rich collection of quotes, encompassing a wide range of genres, periods, and authors. Contributors from around the world submitted their favourite passages, transforming this project into a communal celebration of literature. The concept was taken a step further by tjaap who cleaned up the database and ported it onto a Kindle, complete with a full instructable on how to build you own.

The Kindle Literary Clock by tjapp

Porting to MQTT

MQTT (Message Queuing Telemetry Transport) is a lightweight messaging protocol designed for small sensors and mobile devices optimized for high-latency or unreliable networks. It’s perfect for the Internet of Things (IoT) applications where bandwidth and battery power are at a premium. It is also good for transmitting short text messages to display across multiple devices at the same time, as long as a device is connected to an MQTT broker, it will automatically display messages as they arrive.

As such, as have created a Python script to read the database and publish the time quotes every minute to our MQTT broker on the following address: /personal/ucfnap/timequote (its a little but like tuning a radio, but in the case of MQTT, subscribing to topics).

How It Works:

1. Data Collection: We are using the extensive CSV file containing literary quotes provided by the Kindle Literarty Clock project, where each quote is tagged with a specific minute of the day. To make it work with our script we tidied things up a little.

2. Publishing: This CSV is processed and published via the MQTT feed. Each minute, a new message is sent out containing the current time and the corresponding quote.

3. Subscription: Any device can subscribe to this MQTT feed to receive the quotes in real-time. This could be an e-ink screen, a smart display, or even a mobile application – ie at 10.47 a device would receive the following message:

10.07 am: In a meeting with Rod, Momo and Guy. We are rehearsing the final for the third time, with Rod and Guy taking the parts of the clients, when Rod’s secretary, Lorraine, bursts in. Book: I Don’t Know How She Does It

Applications

E-Ink Screens

Perhaps one of the most elegant implementations of this concept is using e-ink screens. E-ink displays are known for their paper-like readability and low power consumption, making them perfect for a literary clock. For an example of this, you can check out our detailed guide on setting up an e-ink screen with MQTT via our previous project THE: Time Headlines and Environmental Information here.

Literacy Clock using MQTY
Literary Clock using MQTT

Smart Displays and Mobile Apps

Beyond e-ink screens, this feed can be integrated into various smart displays and mobile applications. For example, we have intergrated it into our Home Assistant Dashboard, updating the time with a quote every minute. You could also add it to a HUB75 LED Matrix – below is our example of using an LED Matrix as a general data feed, but by simply changing the MQTT feed, it transforms into a Literary Clock.

 

Setting Up Your Literary Clock

Setting up your device is easy –

1. Choose Your Device: Select a device that can run an MQTT client. This could be an e-ink screen, a Raspberry Pi with a display, or a smartphone.

2. Install an MQTT Libary: There are numerous MQTT libraries available, we mainly use Paho.

3. Subscribe to the Feed: Point your client to the feed /personal/ucfnap/timequote 

Configure your client to display the received messages. Our open MQTT Broker is mqtt.cetools.org on Port 1883

Of course you may not want to bother with Raspberry Pi’s or other about with MQTT, or hack a Kindle – in which case, for those looking for a ready-made commercial version, check out the Author Clock.

The Rather Lovely Author Clock

The Author Clock is a beautifully designed literary clock that comes pre-loaded with thousands of quotes from a wide array of literary works. It’s an excellent choice for those who want to enjoy the literary clock experience without the need for a DIY setup.

With our MQTT messages, any device can now be simply converted into a Literary Clock.

MQTT Scroller

Make a Scrolling Hub75 Matrix Display using a Pimoroni Interstate75W and MQTT

By Making, Posts No Comments

There are many tutorials online on using an LED Matrix to display data—many of them require wiring up a screen, external power supplies, or flashing boards. We wanted to highlight a slightly more accessible way to get an LED Matrix—in our case, a Hub 75, 32×64 pixel up and running using an Interstate75W from Pimoroni. The benefit of the Interstate is that it plugs indirectly into the matrix and can power a single screen directly from the board.

Interstate75W

Interstate75W

We wanted a way to display any data we wanted on the screen with the screen lighting up and data scrolling up as it arrives and then turning off. To use this we use MQTT to load our data (a test feed is included in the scripts – which displays Time, News and Environmental Information) – see below for a demo:

 

We also incorporate manual brightness control and reconnecting for the MQTT for message handling, making it easy to update the display from anywhere. Setting up your own MQTT is beyond this post, but its easier than you may think and once you have one it can be used to display any data, from external feeds such as weather apis through to data from systems such as Home Assistant.

Features

  • Scrolling Text Messages: Display messages that scroll across the HUB75 LED matrix.
  • Manual Brightness Control: Adjust the brightness of the display manually.
  • MQTT Integration: Receive and display messages via MQTT.

Hardware Requirements

To get started, you’ll need the following hardware:

Software Requirements

You’ll also need the following software – all available from our GitHub

  • MicroPython
  • Required MicroPython libraries:
    • interstate75
    • mqtt_as
    • uasyncio

Setup

1. Clone the Repository

First, clone the project repository from GitHub, or just download the files directly:

“`sh
git clone https://github.com/yourusername/interstate75w-mqtt-display.git
cd interstate75w-mqtt-display
“`

2. Upload the Code

Next, upload the code to your microcontroller. You can use tools like Thonny or ampy to do this.

3. Configure WiFi and MQTT

Update the config.py file with your WiFi credentials, the MQTT details can also be updated if you have your own server, if not then leave them for our demo feed.

“`python
config = {
‘ssid’: ‘your_wifi_ssid’,
‘wifi_pw’: ‘your_wifi_password’,
‘server’: ‘mqtt_broker_address’,
‘user’: ‘mqtt_user’,
‘password’: ‘mqtt_password’,
‘port’: 1883,
‘keepalive’: 60,
}
“`

Usage

Run the Script

The script will automatically connect to WiFi and the MQTT broker, then start displaying messages – our MQQ feed displays messages approximatly every 3 minutes.

Constants and Initial Setup

The script defines constants for controlling the scrolling text speed, how long the screen says on for after displaying the message and brightness settings. It also initializes the Interstate75W object:

Constants for controlling scrolling text

BACKGROUND_COLOUR = (0, 0, 0) # Black background to turn off the screen
HOLD_TIME = 2.0
BLANK_SCREEN_TIME = 10.0
BUFFER_PIXELS = 2 # Increased buffer to ensure full scroll off
SCROLL_SPEED_LEVEL = 8 # Set the desired scrolling speed level (1 to 10)
SCROLL_SPEED = 1 / SCROLL_SPEED_LEVEL # Convert to a delay in seconds

Brightness settings

brightness = 50 # Initial brightness (0 to 100)

Do let us know if you make one – we would love to see images of your own set up and we hope this made it a little easier for anyone new looking to run an LED matrix using MQTT.

MQTT Weather Dashboard

Enhancing Live Weather Monitoring with MQTT and Chart.js

By data, Data Visualisation, Weather, Weather (Live), Weather Display No Comments

Introduction

Viewing real-time data from a personal weather station such as a Davis Vantage Pro, a Tempest, or an EcoWhitt device can be complex. However, the majority of systems that process weather data, such as Weather Display, Weewx, or CumlusMx, all have the ability to output MQTT data. This data can be used to display a real-time graph of the data, keeping you engaged with the latest weather updates, and supplemented with any other data which is MQTT-based.

With this in mind, we’ve developed a live weather monitoring dashboard as an illustrative example. This dashboard uses MQTT for real-time data updates and Chart.js for dynamic visualization. We’ve also included a visual indicator for connection status and a brief pulse effect to notify when new data arrives, enhancing the user experience.

MQTT Weather Dashboard

You can view it live at: https://finchamweather.co.uk/weathergraph.htm

The data populates as the page loads – we could of course back load it via a database link, but the aim was to simply use MQTT and have a graphing system that streams in data, its a work in progress but here is how we got it working:

Setting Up the Environment

Before we dive into the code, ensure you have the following libraries included in your HTML:

  • Paho MQTT: for MQTT protocol handling – our MQTT feed is open to use as a test, replace this with your own MQTT details in the main code.
  • Chart.js: for creating dynamic charts
  • Chart.js adapter for date-fns: for handling time scales in charts

Initial HTML Setup

We’ll start by setting up the basic HTML structure. This includes elements for displaying the connection status, forecast, weather statistics, and the weather chart.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <title>Live Weather Graph</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        #mqttStatus {
            margin-bottom: 20px;
            text-align: left;
            font-size: 1.2em;
        }
        .dot {
            height: 20px;
            width: 20px;
            border-radius: 50%;
            display: inline-block;
        }
        .green {
            background-color: green;
        }
        .red {
            background-color: red;
        }
        .orange {
            background-color: orange;
        }
        .pulse-once {
            animation: pulse-once 1s;
        }
        @keyframes pulse-once {
            0% { transform: scale(1); }
            50% { transform: scale(1.2); }
            100% { transform: scale(1); }
        }
        #forecast {
            margin-bottom: 20px;
            text-align: left;
            font-size: 1.2em;
            font-weight: bold;
        }
        #stats {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-bottom: 20px;
            font-size: 1.2em;
            font-weight: bold;
        }
        #stats div {
            padding: 10px 20px;
            border: 1px solid #ccc;
            border-radius: 8px;
            box-shadow: 2px 2px 12px #aaa;
            background-color: #f9f9f9;
        }
        canvas {
            border: 1px solid #ccc;
            box-shadow: 2px 2px 12px #aaa;
        }
    </style>
</head>
<body>
    <div id="mqttStatus"><span id="connectionDot" class="dot red"></span> mqtt: disconnected</div>
    <div id="forecast">Forecast: Loading...</div>
    <div id="stats">
        <div id="maxWindSpeed">Max Wind Speed: 0 mph</div>
        <div id="maxTemp">Max Temperature: 0 °C</div>
        <div id="minTemp">Min Temperature: 0 °C</div>
        <div id="maxPressure">Max Pressure: 0 mbar</div>
        <div id="minPressure">Min Pressure: 0 mbar</div>
    </div>
    <canvas id="weatherChart" width="800" height="400"></canvas>
</body>
</html>

Connecting to MQTT

Next, we set up the MQTT connection. The MQTT client will connect to the broker, subscribe to the necessary topics, and handle messages when they arrive.

// MQTT connection settings
var mqtt;
var reconnectTimeout = 2000;
var host = "mqtt.cetools.org";
var port = location.protocol === 'https:' ? 8081 : 8080;
var options = {
    timeout: 3,
    onSuccess: onConnect,
    onFailure: onFailure,
    useSSL: location.protocol === 'https:',
};
var clientID = "clientID" + parseInt(Math.random() * 100);

function updateConnectionStatus(status) {
    const dot = document.getElementById("connectionDot");
    if (status === "connected") {
        dot.className = "dot green";
        document.getElementById("mqttStatus").innerHTML = `<span class="dot green" id="connectionDot"></span> mqtt: connected`;
    } else if (status === "disconnected") {
        dot.className = "dot red";
        document.getElementById("mqttStatus").innerHTML = `<span class="dot red" id="connectionDot"></span> mqtt: disconnected`;
    } else if (status === "reconnecting") {
        dot.className = "dot orange";
        document.getElementById("mqttStatus").innerHTML = `<span class="dot orange" id="connectionDot"></span> mqtt: reconnecting`;
    }
}

function pulseDot() {
    const dot = document.getElementById("connectionDot");
    dot.classList.add("pulse-once");
    setTimeout(() => {
        dot.classList.remove("pulse-once");
    }, 1000); // Duration of the pulse-once animation
}

function onFailure(message) {
    console.log("Connection Attempt to Host " + host + " Failed: ", message.errorMessage);
    updateConnectionStatus("disconnected");
    setTimeout(MQTTconnect, reconnectTimeout);
}

function onConnect() {
    console.log("Connected ");
    updateConnectionStatus("connected");
    mqtt.subscribe("personal/ucfnaps/downhamweather/loop");
    mqtt.subscribe("personal/ucfnaps/eink/met");
}

function MQTTconnect() {
    console.log("Connecting to " + host + " on port " + port);
    updateConnectionStatus("reconnecting");
    mqtt = new Paho.MQTT.Client(host, port, clientID);
    mqtt.onMessageArrived = onMessageArrived;
    mqtt.onConnectionLost = function(responseObject) {
        if (responseObject.errorCode !== 0) {
            console.log("Connection Lost: " + responseObject.errorMessage);
            updateConnectionStatus("disconnected");
            setTimeout(MQTTconnect, reconnectTimeout);  // Attempt to reconnect
        }
    };
    mqtt.connect(options);
}

window.onload = function() {
    MQTTconnect();
}

Handling Incoming Messages

When messages arrive, we process the data and update the chart. We also update the connection dot to pulse briefly, indicating new data has been received.

let lastUpdate = Date.now();  // Initialize to current time
let firstUpdate = true;  // Flag to ensure first update happens immediately

let maxWindSpeed = 0;
let maxTemp = -Infinity;
let minTemp = Infinity;
let maxPressure = -Infinity;
let minPressure = Infinity;

function updateWindSpeed(windSpeed, timestamp) {
    weatherChart.data .labels.push(timestamp);
    weatherChart.data.datasets[0].data.push(windSpeed);

    // Update max wind speed
    if (windSpeed > maxWindSpeed) {
        maxWindSpeed = windSpeed;
        document.getElementById('maxWindSpeed').innerText = `Max Wind Speed: ${maxWindSpeed} mph`;
    }

    // Limit the number of data points to keep the chart responsive
    if (weatherChart.data.labels.length > 1440) { // Assuming 1 data point per minute, keep 24 hours of data
        weatherChart.data.labels.shift();
        weatherChart.data.datasets[0].data.shift();
    }

    weatherChart.update();
}

function updateOtherMetrics(temperature, solarRadiation, rainAmount, pressure, timestamp) {
    weatherChart.data.datasets[1].data.push({x: timestamp, y: temperature});
    weatherChart.data.datasets[2].data.push({x: timestamp, y: solarRadiation});
    weatherChart.data.datasets[3].data.push({x: timestamp, y: rainAmount > 0 ? rainAmount : null});
    weatherChart.data.datasets[4].data.push({x: timestamp, y: pressure});

    // Update max and min temperature
    if (temperature > maxTemp) {
        maxTemp = temperature;
        document.getElementById('maxTemp').innerText = `Max Temperature: ${maxTemp} °C`;
    }
    if (temperature < minTemp) { minTemp = temperature; document.getElementById('minTemp').innerText = `Min Temperature: ${minTemp} °C`; } // Update max and min pressure if (pressure > maxPressure) {
        maxPressure = pressure;
        document.getElementById('maxPressure').innerText = `Max Pressure: ${maxPressure} mbar`;
    }
    if (pressure < minPressure) { minPressure = pressure; document.getElementById('minPressure').innerText = `Min Pressure: ${minPressure} mbar`; } // Limit the number of data points to keep the chart responsive if (weatherChart.data.labels.length > 1440) { // Assuming 1 data point per minute, keep 24 hours of data
        weatherChart.data.datasets[1].data.shift();
        weatherChart.data.datasets[2].data.shift();
        weatherChart.data.datasets[3].data.shift();
        weatherChart.data.datasets[4].data.shift();
    }

    weatherChart.update();
}

function updateForecast(forecast) {
    document.getElementById('forecast').innerText = `Forecast: ${forecast}`;
}

function onMessageArrived(message) {
    console.log("Message Arrived: " + message.destinationName + " : " + message.payloadString);
    if (message.destinationName === "personal/ucfnaps/downhamweather/loop") {
        const data = JSON.parse(message.payloadString);
        const windSpeed = data['windSpeed_mph'];  // Adjust this key according to your data structure
        const temperature = data['outTemp_C'];  // Adjust this key according to your data structure
        const solarRadiation = data['radiation_Wpm2'];  // Adjust this key according to your data structure
        const rainAmount = data['dayRain_mm'];  // Adjust this key according to your data structure
        const pressure = data['pressure_mbar'];  // Adjust this key according to your data structure

        const nowTimestamp = new Date();

        // Update wind speed every time
        updateWindSpeed(windSpeed, nowTimestamp);

        if (firstUpdate || Date.now() - lastUpdate >= 60000) {
            // Update other metrics every minute
            updateOtherMetrics(temperature, solarRadiation, rainAmount, pressure, nowTimestamp);
            lastUpdate = Date.now();
            firstUpdate = false;  // Ensure subsequent updates follow the interval
        }

        // Pulse the dot when new data arrives
        pulseDot();
    } else if (message.destinationName === "personal/ucfnaps/eink/met") {
        const forecast = message.payloadString;
        updateForecast(forecast);
    }
}

Chart.js Setup

Now, let’s configure Chart.js to visualize the weather data. We will use multiple datasets to display wind speed, temperature, solar radiation, rain amount, and pressure.

// Chart.js setup
const ctx = document.getElementById('weatherChart').getContext('2d');
const weatherChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: [],  // Time labels
        datasets: [{
            label: 'Wind Speed (mph)',
            data: [],
            borderColor: 'rgba(75, 192, 192, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-1',
            tension: 0.1
        },
        {
            label: 'Temperature (°C)',
            data: [],
            borderColor: 'rgba(255, 99, 132, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-2',
            tension: 0.1
        },
        {
            label: 'Solar Radiation (W/m²)',
            data: [],
            borderColor: 'rgba(255, 206, 86, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-3',
            tension: 0.1
        },
        {
            label: 'Rain Amount (mm)',
            data: [],
            borderColor: 'rgba(54, 162, 235, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-4',
            tension: 0.1
        },
        {
            label: 'Pressure (mbar)',
            data: [],
            borderColor: 'rgba(153, 102, 255, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-5',
            tension: 0.1
        }]
    },
    options: {
        responsive: true,
        plugins: {
            legend: {
                position: 'top',
            },
            title: {
                display: true,
                text: 'Live Weather Data'
            },
            decimation: {
                enabled: true,
                algorithm: 'lttb',
                samples: 100,  // Adjust this value as needed for performance
            },
        },
        scales: {
            x: {
                type: 'time',
                time: {
                    unit: 'minute'
                },
                title: {
                    display: true,
                    text: 'Time'
                }
            },
            'y-axis-1': {
                type: 'linear',
                position: 'left',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Wind Speed (mph)'
                }
            },
            'y-axis-2': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Temperature (°C)'
                },
                grid: {
                    drawOnChartArea: false
                }
            },
            'y-axis-3': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Solar Radiation (W/m²)'
                },
                grid: {
                    drawOnChartArea: false
                }
            },
            'y-axis-4': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Rain Amount (mm)'
                },
                grid: {
                    drawOnChartArea: false
                }
            },
            'y-axis-5': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Pressure (mbar)'
                },
                grid: {
                    drawOnChartArea: false
                }
            }
        },
        interaction: {
            intersect: false,
            mode: 'nearest',
        },
        elements: {
            line: {
                cubicInterpolationMode: 'monotone',
            },
        },
    }
});

Conclusion

By integrating MQTT and Chart.js, it is possible to create a dynamic and real-time weather monitoring dashboard. The connection status indicator provides immediate feedback on the connection state, and the pulsing effect when new data arrives enhances user experience by visually notifying them of updates.

This setup can be further extended by adding more datasets, customizing the chart’s appearance, or integrating additional sensors. The data of course couple be from any feed, but real-time weather monitoring provides a good example of how IoT and web technologies can be combined to create realtime dashboards.

Close Menu

About Salient

The Castle
Unit 345
2500 Castle Dr
Manhattan, NY

T: +216 (0)40 3629 4753
E: hello@themenectar.com