Code Library
Shop DataPythonWindows · Python 3.8+ · xlwings · Microsoft ExcelMIT licenseAdvanced

Push live shop-floor numbers into an open Excel dashboard (xlwings)

Nobody on a shop floor wants to learn a new dashboard app — they already know Excel. This script is the other half of the openpyxl report: instead of writing a file once, it connects to a workbook someone already has open and updates five cells every second, live, while Excel does what it's always done — formatting, conditional colors, a chart if you want one. Tested here against a real, running Excel instance, including a real formatting trap it caught along the way.

Before you run it

  • pip install xlwings
  • Microsoft Excel installed and running (Windows) — this drives Excel over COM, it doesn't work headless
  • A workbook named dashboard.xlsx already open, with a sheet named Dashboard

The code

GitHub
"""Push live shop-floor numbers into an already-open Excel workbook, once a
second - the "Excel front-end, Python back-end" pattern for a dashboard
nobody has to learn a new tool to read.

Usage:  python xlwings_dashboard.py
"""

import random
import time

import xlwings as xw

WORKBOOK_NAME = "dashboard.xlsx"   # must already be open in Excel
SHEET_NAME = "Dashboard"


def read_live_numbers():
    """Stand-in for a real data source (PLC tag, database, FOCAS poller...).
    Replace this with whatever actually produces your shop-floor numbers."""
    return {
        "parts_today": random.randint(280, 320),
        "scrap_today": random.randint(2, 12),
        "cycle_time_s": round(random.uniform(38, 45), 1),
        "machine_status": random.choice(["RUNNING", "RUNNING", "RUNNING", "HOLD"]),
    }


def main():
    wb = xw.Book(WORKBOOK_NAME)  # connects to the ALREADY OPEN workbook
    sheet = wb.sheets[SHEET_NAME]
    sheet["B6"].number_format = "@"  # Text - a time-like string would otherwise
                                      # get reinterpreted as an Excel time serial

    print(f"Connected to {WORKBOOK_NAME} / {SHEET_NAME}. Ctrl+C to stop.")
    try:
        while True:
            data = read_live_numbers()
            sheet["B2"].value = data["parts_today"]
            sheet["B3"].value = data["scrap_today"]
            sheet["B4"].value = data["cycle_time_s"]
            sheet["B5"].value = data["machine_status"]
            sheet["B6"].value = time.strftime("%H:%M:%S")
            time.sleep(1)
    except KeyboardInterrupt:
        print("\nStopped. The workbook keeps whatever it last showed.")


if __name__ == "__main__":
    main()

What you get

$ python xlwings_dashboard.py
Connected to dashboard.xlsx / Dashboard. Ctrl+C to stop.
^C
Stopped. The workbook keeps whatever it last showed.

dashboard.xlsx — Dashboard sheet

   A                 B
2  Parts today       294
3  Scrap today       2
4  Cycle time (s)    44.1
5  Machine status    RUNNING
6  Last update       22:19:26   <- stays literal text (number_format="@")

How it works

  • xw.Book(WORKBOOK_NAME) connects to an already-open workbook instead of creating a new one — the whole point of this pattern is that someone already has the file open on a monitor, and the script updates it live behind the scenes.
  • Setting number_format = "@" (Text) on the timestamp cell before writing to it is the fix for a real trap this script hit in testing: write a string like "14:32:07" to a plain cell and Excel silently reinterprets it as a time serial number, showing a bare decimal fraction instead of the text you sent.
  • read_live_numbers() is a deliberate stand-in — swap it for a FOCAS poller, a database query, or an OPC UA read, and everything downstream (writing cells, the dashboard itself) doesn't change.
  • No custom UI, no PyQt, no WinForms — Excel already does formatting, conditional colors, and charts; this script's only job is keeping five cells current.

Gotchas & honest limits

  • The workbook must already be openxw.Book() raises if it can't find a workbook by that name among currently-open Excel instances, and it does not silently create one.
  • String values that look like times, dates, or numbers get reinterpreted by Excel unless the target cell is pre-formatted as Text — this bit the timestamp cell during testing; watch for it on any other text-that-looks-numeric field.
  • This writes cell-by-cell in a tight loop — fine for five values once a second; batch a full range write (sheet["B2:B6"].value = [[...]]) if you're updating dozens of cells at that cadence.
  • xlwings drives Excel over COM, which means this only runs on Windows with Excel installed — there's no cross-platform equivalent for the live-write half of this pattern. Reading/writing .xlsx without Excel open is a different, portable job — see the openpyxl report script.

Goes deeper

Want this adapted to your shop — or built into a real tool?

Samples are the free 80%. The last 20% is the part I do for a living.

Get in touch
Home
Blog
Tools
Code
Email
LinkedIn
Résumé