HorizonPLC
HorizonPLC: A Modular Open-Source PLC Framework Built in Espruino JavaScript
요약
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
두 축의 결론을 종합하면, 저장소 자체의 산업 도입은 확인되지 않으나, 그 필요성에 대한 개발자 커뮤니티의 수요는 명확히 확인됩니다. HorizonPLC는 그 수요에 대한 실제 구현 시도로 볼 수 있습니다.
아키텍처
HorizonPLC는 3단계 부트 시퀀스(.boot0 → .boot1 → .boot2)로 시작되며, 필드 레이어에서 서버 레이어까지 이벤트 기반으로 연결됩니다.
기술 배경
하드웨어 TCP/IP 오프로딩 (W5500)
W5500은 TCP/IP 스택, MAC, PHY를 하나의 칩에 통합해 MCU 자원 소모 없이 네트워크 처리를 전담하는 하드와이어드 컨트롤러입니다. lwIP 같은 소프트웨어 스택이 SRAM과 CPU 사이클을 잠식하는 것과 달리, W5500은 SPI 레지스터 접근만으로 소켓을 다룰 수 있습니다. HorizonPLC처럼 JS 인터프리터 자체가 이미 상당한 메모리를 점유하는 환경에서는 네트워크 처리를 MCU에서 완전히 분리하는 이 접근이 특히 유효합니다.
→ 참고: WIZnet W5500 Datasheet
Espruino: 마이크로컨트롤러용 JavaScript 런타임
Espruino는 STM32, ESP32, nRF52 등 다양한 MCU에서 JS 코드를 직접 인터프리트해 실행하는 펌웨어입니다. require()를 통한 동적 모듈 로딩, Flash 파일시스템 기반 부팅(*.boot0 자동 실행) 등의 특성 덕분에, HorizonPLC는 C/C++ 재컴파일 없이 JSON 설정 변경만으로 하드웨어 재구성이 가능한 구조를 만들 수 있었습니다.
→ 참고: Espruino 공식 사이트
MQTT 프로토콜
MQTT는 경량 발행/구독(Pub/Sub) 프로토콜로, 제한된 대역폭과 간헐적 연결에도 강합니다. HorizonPLC의 plcProxyMQTT는 브로커 명령을 시스템 서비스로 라우팅하고, 반대로 서비스 메시지를 브로커로 전달하는 양방향 이벤트 브릿지 역할을 하며, 이는 MQTT의 토픽 기반 구조를 그대로 활용한 설계입니다.
→ 참고: 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
- STM32H750 + W5500 PLC TCP Server: HorizonPLC와 동일한 STM32 + W5500 하드웨어 구조의 PLC형 컨트롤러입니다. 다만 C/C++ 기반 Raw TCP 서버로 구현되어, HorizonPLC의 JS 기반 MQTT/이벤트 구조와는 통신 계층이 다릅니다.
→ 프로젝트 링크: STM32H750 + W5500 PLC TCP Server
- DINO-PLC-V2: W5500 기반의 오픈소스 소프트 PLC라는 점에서 HorizonPLC와 목적이 같습니다. 다만 ESP32 + Mitsubishi FX2N 래더 로직 호환에 특화된 반면, HorizonPLC는 특정 PLC 규격 호환보다 범용 모듈형 구조를 지향합니다.
→ 프로젝트 링크: 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()호출 전 **고정 5000mssetTimeout**에 의존해, 연결 실패 시 재시도 로직이 없음- 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
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.
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
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
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
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.jsonsplits 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
- 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
- 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
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 5000mssetTimeoutbefore callingsetIP(), 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.

