---
title: "HorizonPLC"
url: "https://maker.wiznet.io/scott/projects/horizonplc/"
markdown_url: "https://maker.wiznet.io/scott/projects/horizonplc/md"
type: "UCC: User Created Content"
author: "Konkery"
author_url: "https://github.com/Konkery/HorizonPLC"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "Konkery"
original_url: "https://github.com/Konkery/HorizonPLC"
published: "2026-07-09"
language: "en"
hardware: ["WIZnet W5500"]
likes: 0
views: 192
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# HorizonPLC

> HorizonPLC: A Modular Open-Source PLC Framework Built in Espruino JavaScript

Original author: Konkery (source: https://github.com/Konkery/HorizonPLC)

## Components

- **WIZnet W5500** x 1 ([docs](https://docs.wiznet.io/Product/Chip/Ethernet/W5500))

WIZnet parts: W5500 ([Datasheet](https://docs.wiznet.io/Product/Chip/Ethernet/W5500/datasheet?utm_source=maker&utm_medium=project&utm_campaign=w5500), [product hub](https://maker.wiznet.io/products/w5500/))

## Documents and links

- [git](https://github.com/Konkery/HorizonPLC) (code)

## Article

### 요약

HorizonPLC는 **Espruino**(마이크로컨트롤러용 JavaScript 런타임) 위에서 동작하는 오픈소스 PLC 프레임워크 **Horizon Automated**의 필드 레벨 구현체입니다. 센서·액추에이터를 통일된 채널 인터페이스로 추상화하고, **WIZnet W5500**을 통한 유선 Ethernet 또는 ESP8266/ESP32 WiFi 중 하나를 선택해 MQTT 브로커와 데이터를 주고받는 구조를 갖췄습니다. JS 코드 레벨에 `W5500`이 명시적으로 하드코딩되어 있다는 점에서, 저자원 MCU용 JS 생태계 안에서 WIZnet의 하드웨어 TCP/IP 오프로딩이 실제로 어떻게 활용되는지 보여주는 흥미로운 레퍼런스입니다.

### 개요

Mitsubishi FX 시리즈처럼 소규모 공장 자동화 시장을 오래 지배해온 상용 PLC는 **전용 프로그래밍 소프트웨어와 폐쇄형 통신 프로토콜, 높은 하드웨어 단가**라는 진입 장벽을 가지고 있습니다. HorizonPLC는 이 문제에 **JavaScript**로 정면 대응합니다. Espruino가 제공하는 JS 인터프리터 위에 센서/액추에이터 처리, 네트워크 연결, MQTT 게이트웨이까지 모두 `.min.js` 모듈로 구성해, STM32 또는 ESP32의 Flash 메모리에 업로드만 하면 동작하는 구조를 지향합니다. 개발자는 코드를 다시 작성하지 않고 JSON 설정 파일(`init.json`, `device.json`, `services.json`, `network.json`) 수정만으로 하드웨어 구성을 바꿀 수 있습니다.

### 도입 배경 / 왜 필요한가

**저장소 자체 도입 사례**: 확인 불가. Star 0 / Fork 3 수준으로, 상업적 채택이나 언론 보도 등 외부 레퍼런스는 발견되지 않았습니다.

**산업적·커뮤니티 필요성 근거**: 확인됨. Espruino 공식 포럼에는 2019년부터 "**Espruino PLC**"라는 제목의 논의가 존재하며, 저비용 MCU와 JS 조합으로 PLC를 구현하려는 수요가 커뮤니티 차원에서 꾸준히 제기되어 왔습니다. HorizonPLC의 주요 기여자인 Konkery 역시 같은 포럼에서 Espruino의 STM32/ESP32 활용에 대해 활발히 논의해온 인물로 확인됩니다.

→ 참고: [Espruino Forum: Idea - Espruino PLC](http://forum.espruino.com/conversations/342039/)

두 축의 결론을 종합하면, **저장소 자체의 산업 도입은 확인되지 않으나, 그 필요성에 대한 개발자 커뮤니티의 수요는 명확히 확인됩니다.** HorizonPLC는 그 수요에 대한 실제 구현 시도로 볼 수 있습니다.

### 아키텍처

HorizonPLC는 3단계 부트 시퀀스(`.boot0` → `.boot1` → `.boot2`)로 시작되며, 필드 레이어에서 서버 레이어까지 이벤트 기반으로 연결됩니다.

![](https://maker.wiznet.io/upload/ckeditor5/842489838%5F1783615400%2Epng)

### 기술 배경

#### 하드웨어 TCP/IP 오프로딩 (W5500)

W5500은 TCP/IP 스택, MAC, PHY를 하나의 칩에 통합해 **MCU 자원 소모 없이 네트워크 처리를 전담**하는 하드와이어드 컨트롤러입니다. lwIP 같은 소프트웨어 스택이 SRAM과 CPU 사이클을 잠식하는 것과 달리, W5500은 SPI 레지스터 접근만으로 소켓을 다룰 수 있습니다. HorizonPLC처럼 **JS 인터프리터 자체가 이미 상당한 메모리를 점유하는 환경**에서는 네트워크 처리를 MCU에서 완전히 분리하는 이 접근이 특히 유효합니다.

→ 참고: [WIZnet W5500 Datasheet](https://www.wiznet.io/product-item/w5500/)

#### Espruino: 마이크로컨트롤러용 JavaScript 런타임

Espruino는 STM32, ESP32, nRF52 등 다양한 MCU에서 JS 코드를 직접 인터프리트해 실행하는 펌웨어입니다. `require()`를 통한 동적 모듈 로딩, Flash 파일시스템 기반 부팅(`*.boot0` 자동 실행) 등의 특성 덕분에, HorizonPLC는 C/C++ 재컴파일 없이 **JSON 설정 변경만으로 하드웨어 재구성**이 가능한 구조를 만들 수 있었습니다.

→ 참고: [Espruino 공식 사이트](https://www.espruino.com/)

#### MQTT 프로토콜

MQTT는 경량 발행/구독(Pub/Sub) 프로토콜로, 제한된 대역폭과 간헐적 연결에도 강합니다. HorizonPLC의 `plcProxyMQTT`는 브로커 명령을 시스템 서비스로 라우팅하고, 반대로 서비스 메시지를 브로커로 전달하는 **양방향 이벤트 브릿지** 역할을 하며, 이는 MQTT의 토픽 기반 구조를 그대로 활용한 설계입니다.

→ 참고: [MQTT.org](https://mqtt.org/)

### 기술 특징

- **채널(Channel) 기반 센서 추상화**: 모든 센서를 개별 측정값 단위인 "채널"로 분리해, Suppression → Linear Transform → Filter → Alarm zone 순서로 자동 처리

- **프록시 계층 분리**: DeviceManager가 MQTT/WebSocket과 직접 통신하지 않고 Proxy를 경유하게 해, 서버 프로토콜이 바뀌어도 필드 로직은 영향받지 않음

- **JSON 설정 기반 무중단 재구성**: `ports.json`으로 STM32/ESP32 핀맵을 분리해 동일 코드베이스로 듀얼 타겟 지원

### WIZnet 적용 구조

**실제 사용**: **W5500**이 `plcNetwork` 모듈 코드에 명시적으로 하드코딩되어 있습니다(`this._ChipType = 'W5500';`). `EtherSequence()` 메서드가 Espruino 빌트인 `require('WIZnet').connect(bus, cs)`를 호출해 SPI 버스로 칩을 초기화하고, `setIP()`로 DHCP IP를 획득합니다. 예시 설정 파일에는 SPI2(MOSI B15 / MISO B14 / SCK B13 / CS C8) 배선이 제시되어 있습니다.

network.json의 flag 값에 따라 **WiFi(ESP8266/ESP32)와 Ethernet(W5500) 중 하나를 선택**하는 병렬 구조이며, 현재 버전은 **클라이언트 모드만 지원**합니다.

**[추정]** PoE 지원이나 IP 프래그멘테이션 대응 여부는 코드에서 확인되지 않아 **미확인** 상태입니다.

### WIZnet Makers 유사 사례

- **Pixl.js Bluetooth to Ethernet MQTT Bridge**: HorizonPLC와 동일하게 **Espruino JS 런타임 + WIZnet Ethernet + MQTT** 조합을 사용합니다. 다만 이 프로젝트는 BLE 애드버타이징 패킷을 MQTT로 전달하는 단일 브릿지 기능에 그치는 반면, HorizonPLC는 센서·액추에이터·프록시·게이트웨이를 아우르는 전체 프레임워크입니다.

→ 프로젝트 링크: [Pixl.js Bluetooth to Ethernet MQTT Bridge](https://maker.wiznet.io/mason/projects/Pixljs-Bluetooth-to-Ethernet-MQTT-Bridge-m/)

- **STM32H750 + W5500 PLC TCP Server**: HorizonPLC와 동일한 **STM32 + W5500** 하드웨어 구조의 PLC형 컨트롤러입니다. 다만 C/C++ 기반 Raw TCP 서버로 구현되어, HorizonPLC의 JS 기반 MQTT/이벤트 구조와는 통신 계층이 다릅니다.

→ 프로젝트 링크: [STM32H750 + W5500 PLC TCP Server](https://maker.wiznet.io/sophia/projects/stm32h750-w5500-plc-tcp-server/)

- **DINO-PLC-V2**: W5500 기반의 오픈소스 소프트 PLC라는 점에서 HorizonPLC와 목적이 같습니다. 다만 ESP32 + Mitsubishi FX2N 래더 로직 호환에 특화된 반면, HorizonPLC는 특정 PLC 규격 호환보다 범용 모듈형 구조를 지향합니다.

→ 프로젝트 링크: [DINO-PLC-V2](https://maker.wiznet.io/scott/projects/dino-plc-v2/)

세 사례 모두 W5500을 **필드 레벨 통신의 안정성 확보 수단**으로 채택했다는 공통점이 있으며, 이는 소규모 오픈소스 PLC 생태계에서 W5500이 검증된 선택지로 자리잡았음을 보여줍니다.

| 항목 | HorizonPLC | Pixl.js MQTT Bridge | STM32H750 PLC TCP Server | DINO-PLC-V2 |
| --- | --- | --- | --- | --- |
| 펌웨어/플랫폼 | Espruino (JS) | Espruino (JS) | C/C++ (Bare-metal) | Arduino (C++) |
| MCU | STM32 / ESP32 | Espruino 보드(Puck.js/Pixl.js) | STM32H750 | ESP32 |
| 네트워크 칩 | W5500 | WIZnet 어댑터(모델 미상) | W5500 | W5500 |
| 통신 프로토콜 | MQTT, WebSocket | MQTT | Raw TCP | Modbus TCP, MQTT |
| 주요 기능 | 범용 센서/액추에이터 PLC 프레임워크 | BLE→Ethernet MQTT 브릿지 | TCP 기반 I/O 서버 | FX2N 호환 래더로직 PLC |
| 저장소 활성 상태 | 2024년 12월 이후 중단 | 미상 | 미상 | 미상 |

표에서 드러나듯, 네 프로젝트 모두 **W5500을 필드 네트워크의 핵심 인터페이스로 통합**했다는 설계 철학을 공유합니다. HorizonPLC의 차별점은 특정 프로토콜이나 PLC 규격에 종속되지 않고, **JSON 설정만으로 재구성 가능한 범용 모듈 체계**를 지향한다는 점입니다.

### 비즈니스 가치

- **RF 간섭 환경 대응**: 모터·용접 장비 등으로 2.4GHz가 혼잡한 공장 환경에서 W5500 유선 연결로 결정론적 데이터 전송 확보

- **저비용 커스텀 PLC**: 상용 PLC의 폐쇄형 프로토콜 대신 JS 설정 기반으로 소규모 팹·스타트업이 직접 구성 가능

- **SCADA/Node-RED 연동**: MQTT/WebSocket 게이트웨이 구조가 기존 산업 모니터링 스택과 자연스럽게 통합

- **원격 모니터링**: 채널 기반 센서 추상화로 다양한 필드 장비를 동일한 인터페이스로 원격 관리

### 한계 및 개선 방향

**현재 한계**

- `EtherSequence()`가 `setIP()` 호출 전 **고정 5000ms `setTimeout`**에 의존해, 연결 실패 시 재시도 로직이 없음

- README에 **클라이언트 모드만 지원**한다고 명시되어 있어 서버 모드·PoE는 다루지 않음

- 2024년 12월 중순 이후 커밋이 없어 초기 단계에 머문 상태이며, 라이선스도 전 README에서 "////"(미정)로 남아있음

**개선 방향**

- Espruino의 콜백 기반 에러 핸들링을 W5500 연결 시퀀스에도 적용해 재시도·타임아웃 처리 강화

- WIZnet 칩의 8개 독립 소켓을 활용해 MQTT와 Modbus TCP 등 복수 프로토콜을 동시 처리하는 구조로 확장 가능

- 커뮤니티 차원의 수요(Espruino PLC 논의)를 고려하면, 유지보수 재개 시 소규모 PLC 대체 솔루션으로서의 가치는 유효

### FAQ

**Q1. HorizonPLC를 도입하려면 난이도가 높은가요?** JSON 설정 파일(init/device/services/network/ports) 작성이 핵심이며, 코드 재컴파일 없이 Flash 업로드만으로 구성을 바꿀 수 있어 진입 장벽은 낮은 편입니다.

**Q2. Ethernet(W5500)과 WiFi 중 어떤 것을 선택해야 하나요?** `network.json`의 flag로 선택합니다. RF 간섭이 심하거나 안정적인 유선 연결이 필요하면 W5500, 배선이 어려운 환경이면 ESP8266/ESP32 WiFi가 적합합니다.

**Q3. STM32와 ESP32 중 어떤 MCU를 선택해야 하나요?** `ports.json`이 두 플랫폼별로 분리되어 있어 코드 변경 없이 전환 가능합니다. 다만 저장소 예시 배선(SPI2 기반 W5500 연결)은 STM32 기준으로 작성되어 있어, ESP32 조합 시 별도 검증이 필요합니다.

**Q4. 유지보수는 잘 되고 있나요?** 2024년 12월 중순 이후 커밋 활동이 없어, 도입 시 자체 포크·유지보수를 전제해야 합니다.

**Q5. BOM(자재비)에 미치는 영향은?** W5500 모듈 추가 비용이 발생하지만, 상용 PLC 대비 전체 하드웨어 단가는 낮게 유지할 수 있습니다.

---

## HorizonPLC: A Modular Open-Source PLC Framework Built in Espruino JavaScript

### Summary

HorizonPLC is the field-level implementation of **Horizon Automated**, an open-source PLC framework that runs on **Espruino**, a JavaScript runtime for microcontrollers. It abstracts sensors and actuators into a unified channel interface and connects to an MQTT broker over either wired Ethernet via **WIZnet W5500** or WiFi via ESP8266/ESP32. The **W5500** chip type is hardcoded directly into the source, making this project a concrete reference for how WIZnet's hardware TCP/IP offloading gets used inside a resource-constrained JS-on-MCU ecosystem.

### Overview

Commercial PLCs like the Mitsubishi FX series have long dominated small-scale factory automation, but they come with **proprietary programming software, closed communication protocols, and high hardware costs**. HorizonPLC addresses this head-on with JavaScript. Built on top of the Espruino interpreter, it packages sensor/actuator handling, network connectivity, and MQTT gateway functions into `.min.js` modules that only need to be uploaded to an STM32 or ESP32's flash storage. Developers can reconfigure hardware setups purely by editing JSON files (`init.json`, `device.json`, `services.json`, `network.json`) without touching the code.

### Why This Matters

**Real-world adoption of the repository itself**: Not confirmed. With 0 stars and 3 forks, no external references, press coverage, or commercial deployment could be found.

**Industry and community need**: Confirmed. The Espruino community forum has hosted a thread titled "Idea: Espruino PLC" since 2019, reflecting a recurring demand for low-cost MCU-plus-JS PLC implementations. Notably, Konkery, one of HorizonPLC's main contributors, is an active participant in the same forum discussing Espruino deployments on STM32 and ESP32.

→ Source: [Espruino Forum: Idea - Espruino PLC](http://forum.espruino.com/conversations/342039/)

Taken together, the repository's own industrial adoption is unconfirmed, but the underlying demand for exactly this kind of project is well documented within the developer community. HorizonPLC reads as a direct attempt to answer that demand.

### Architecture

HorizonPLC boots in three stages (`.boot0` → `.boot1` → `.boot2`) and connects the field layer to the server layer through an event-driven pipeline.

![](https://maker.wiznet.io/upload/ckeditor5/842489838%5F1783615690%2Epng)

### Technology Background

#### Hardware TCP/IP Offloading (W5500)

The W5500 integrates a TCP/IP stack, MAC, and PHY into a single chip, **handling network processing entirely offloaded from the MCU**. Unlike software stacks such as lwIP that consume SRAM and CPU cycles, the W5500 exposes sockets through simple SPI register access. In an environment like HorizonPLC's, where **the JS interpreter itself already occupies significant memory**, offloading networking away from the MCU entirely is especially valuable.

→ Source: [WIZnet W5500 Datasheet](https://www.wiznet.io/product-item/w5500/)

#### Espruino: A JavaScript Runtime for Microcontrollers

Espruino is firmware that interprets and runs JavaScript directly on MCUs including STM32, ESP32, and nRF52. Features like dynamic module loading through `require()` and automatic execution of `.boot0` files from flash storage let HorizonPLC reconfigure hardware setups **purely through JSON edits, with no C/C++ recompilation required**.

→ Source: [Espruino Official Site](https://www.espruino.com/)

#### MQTT Protocol

MQTT is a lightweight publish/subscribe protocol built to tolerate limited bandwidth and intermittent connections. HorizonPLC's `plcProxyMQTT` acts as a **bidirectional event bridge**, routing broker commands to system services and forwarding service messages back to the broker — a design that leans directly on MQTT's topic-based structure.

→ Source: [MQTT.org](https://mqtt.org/)

### Technical Highlights

- **Channel-based sensor abstraction**: Every sensor is split into individual measurement "channels," each auto-processed through Suppression → Linear Transform → Filter → Alarm zone check

- **Proxy layer separation**: DeviceManager never talks to MQTT or WebSocket directly — it goes through a proxy, so field logic stays unaffected even if server protocols change

- **JSON-driven reconfiguration**: `ports.json` splits STM32 and ESP32 pin maps, letting the same codebase support dual targets

### Where WIZnet Fits

**Confirmed usage**: **W5500** is hardcoded directly into the `plcNetwork` module (`this._ChipType = 'W5500';`). The `EtherSequence()` method calls Espruino's built-in `require('WIZnet').connect(bus, cs)` to initialize the chip over an SPI bus, then calls `setIP()` to obtain a DHCP address. The example configuration wires it over SPI2 (MOSI B15 / MISO B14 / SCK B13 / CS C8).

The `network.json` flag lets developers **choose between WiFi (ESP8266/ESP32) and Ethernet (W5500)** in parallel, though the current version supports **client mode only**.

**[Inferred]** PoE support and handling of IP fragmentation edge cases are not addressed in the code and remain **unconfirmed**.

### Similar Projects on WIZnet Makers

- **Pixl.js Bluetooth to Ethernet MQTT Bridge**: Shares the exact same software stack as HorizonPLC — **Espruino JS runtime + WIZnet Ethernet + MQTT**. The difference is scope: this project only bridges BLE advertising packets to MQTT, while HorizonPLC implements a full framework spanning sensors, actuators, proxies, and gateways.

→ Project link: [Pixl.js Bluetooth to Ethernet MQTT Bridge](https://maker.wiznet.io/mason/projects/Pixljs-Bluetooth-to-Ethernet-MQTT-Bridge-m/)

- **STM32H750 + W5500 PLC TCP Server**: Matches HorizonPLC's **STM32 + W5500** hardware structure in a PLC-like controller. It's implemented in bare-metal C/C++ as a raw TCP server, so the communication layer differs from HorizonPLC's JS-based MQTT/event model.

→ Project link: [STM32H750 + W5500 PLC TCP Server](https://maker.wiznet.io/sophia/projects/stm32h750-w5500-plc-tcp-server/)

- **DINO-PLC-V2**: Shares the same purpose as HorizonPLC — an open-source soft PLC built on W5500. It specializes in ESP32 hardware and Mitsubishi FX2N ladder-logic compatibility, whereas HorizonPLC targets general-purpose modularity rather than a specific PLC standard.

→ Project link: [DINO-PLC-V2](https://maker.wiznet.io/scott/projects/dino-plc-v2/)

All three projects adopt W5500 as **the reliability backbone of their field-level communication**, showing that W5500 has become a proven choice within the small-scale open-source PLC ecosystem.

| Item | HorizonPLC | Pixl.js MQTT Bridge | STM32H750 PLC TCP Server | DINO-PLC-V2 |
| --- | --- | --- | --- | --- |
| Firmware/Platform | Espruino (JS) | Espruino (JS) | C/C++ (bare-metal) | Arduino (C++) |
| MCU | STM32 / ESP32 | Espruino board (Puck.js/Pixl.js) | STM32H750 | ESP32 |
| Network chip | W5500 | WIZnet adapter (model unconfirmed) | W5500 | W5500 |
| Communication protocol | MQTT, WebSocket | MQTT | Raw TCP | Modbus TCP, MQTT |
| Core function | General-purpose sensor/actuator PLC framework | BLE-to-Ethernet MQTT bridge | TCP-based I/O server | FX2N-compatible ladder-logic PLC |
| Repository activity | Stalled since December 2024 | Unconfirmed | Unconfirmed | Unconfirmed |

As the table shows, all four projects share a design philosophy of **integrating W5500 as the core field-network interface**. HorizonPLC's distinguishing trait is that it isn't tied to a specific protocol or PLC standard — it aims for a **general-purpose module system reconfigurable entirely through JSON**.

### Business Value / Use Cases

- **RF-congested environments**: Wired W5500 connectivity provides deterministic data transmission on factory floors where 2.4GHz is crowded by motors and welding equipment

- **Low-cost custom PLCs**: JSON-driven configuration lets small workshops and startups build custom controllers instead of relying on closed commercial protocols

- **SCADA/Node-RED integration**: The MQTT/WebSocket gateway structure integrates naturally with existing industrial monitoring stacks

- **Remote monitoring**: Channel-based sensor abstraction lets diverse field devices be managed remotely through a single interface

### Limitations and Future Improvements

**Current limitations**

- `EtherSequence()` relies on a **fixed 5000ms **`**setTimeout**` before calling `setIP()`, with no retry logic if the connection fails

- The README explicitly states **client mode only** — server mode and PoE are out of scope

- Commit activity stopped in mid-December 2024, suggesting an early-stage project; even the license field is still marked "////" (undecided) across every README

**Improvement directions**

- Applying Espruino's callback-based error handling to the W5500 connection sequence would strengthen retry and timeout behavior

- The W5500's 8 independent sockets could be leveraged to run multiple protocols concurrently, such as MQTT alongside Modbus TCP

- Given the confirmed community demand behind "Espruino PLC," resuming maintenance could position this as a viable low-cost PLC alternative

### FAQ

**Q1. Is HorizonPLC difficult to adopt?** The core task is writing JSON configuration files (init/device/services/network/ports). No recompilation is needed — just re-uploading files to flash — which keeps the barrier to entry relatively low.

**Q2. Should I choose Ethernet (W5500) or WiFi?** This is set via a flag in `network.json`. Choose W5500 for environments with heavy RF interference or where a stable wired connection is required; choose ESP8266/ESP32 WiFi where wiring is impractical.

**Q3. Should I choose STM32 or ESP32?** `ports.json` is split by platform, so switching requires no code changes. That said, the example wiring for W5500 (over SPI2) is written for STM32, so an ESP32 pairing would need separate verification.

**Q4. Is this actively maintained?** No commits have landed since mid-December 2024, so adopting it means planning for your own fork and maintenance.

**Q5. What's the impact on BOM cost?** Adding a W5500 module raises component cost slightly, but total hardware cost remains well below that of commercial PLCs.

---

Source: https://maker.wiznet.io/scott/projects/horizonplc/
