> **Note:** This is a vibe-coded fork of [gabrielkim13/json-logic-cpp](https://github.com/gabrielkim13/json-logic-cpp).

# JsonLogic

Run [JsonLogic](https://jsonlogic.com/) rules with
[ArduinoJson](https://arduinojson.org/) on ESP8266, ESP32, and other Arduino
cores that provide the required C++17 standard-library features.

JsonLogic represents logic as JSON data instead of compiled C++ code. Your
firmware can load a rule from flash, a web API, MQTT, a configuration portal,
or the serial port and evaluate it against current sensor or device data. This
allows users and administrators to change behavior without rebuilding and
flashing the firmware.

Typical uses include:

- turning relays, lights, fans, pumps, or alarms on when conditions match
- user-configurable sensor thresholds and schedules
- validating configuration or incoming messages
- selecting modes, notifications, or access policies
- sharing the same rule format between a web application and a device

The rule decides whether or what to do. Your firmware remains responsible for
mapping a trusted action name to the actual hardware operation.

## Installation

### Arduino IDE

Search for **JsonLogic** in Library Manager and install it. ArduinoJson 7.4.2
or newer is declared as a dependency and will be installed automatically.

The public include is:

```cpp
#include <JsonLogic.h>
```

Arduino's Library Manager submission checks reject the `ArduinoJsonLogic`
name for a third-party library, so the registry package and header are named
`JsonLogic`.

This release targets ESP8266 and ESP32. Classic AVR boards such as the Arduino
Uno are not supported because their standard library does not provide the STL
features used by the rule engine.

### PlatformIO

Add **JsonLogic** from the PlatformIO Registry to your project's `lib_deps`.
ArduinoJson is declared as a dependency and will be installed automatically.

```ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
  JsonLogic
```

## Basic Usage

```cpp
#include <ArduinoJson.h>
#include <JsonLogic.h>

using json_logic::Json;
using json_logic::JsonLogic;

Json rule;
Json data;

deserializeJson(rule, R"({"<":[{"var":"temperature"},30]})");
deserializeJson(data, R"({"temperature":24.5})");

JsonLogic* engine = JsonLogic::GetInstance();
Json result = engine->Apply(rule, data);

if (engine->HasError())
{
  Serial.println(engine->GetLastError().c_str());
}
else if (result.as<bool>())
{
  Serial.println("The rule matched");
}
```

Inputs are ArduinoJson `JsonVariantConst` views. Results are owning
`JsonDocument` values exposed as `json_logic::Json`.

## Dynamic User Rules

A rule can be stored separately from the firmware:

```json
{
  "action": "fan_on",
  "when": {
    "and": [
      { ">": [{ "var": "temperature" }, 28] },
      { ">": [{ "var": "humidity" }, 65] }
    ]
  }
}
```

Evaluate the `when` value against live data:

```json
{
  "temperature": 31.5,
  "humidity": 72
}
```

The result is `true`, so application code can dispatch the trusted `fan_on`
action. A configuration UI can later replace the rule with different
thresholds or conditions without changing the device firmware.

See:

- `examples/Basic` for one rule evaluation
- `examples/DynamicRules` for replacing a rule over Serial and dispatching an action
- `examples/IoTRules` for evaluating several automation rules

## Supported Operations

- Data: `var`, `missing`, `missing_some`
- Logic: `if`, `==`, `===`, `!=`, `!==`, `!`, `!!`, `or`, `and`
- Numeric: `>`, `>=`, `<`, `<=`, `max`, `min`, `+`, `-`, `*`, `/`, `%`
- Arrays: `map`, `reduce`, `filter`, `all`, `none`, `some`, `merge`, `in`
- Strings and diagnostics: `cat`, `substr`, `log`

Refer to [JsonLogic operations](https://jsonlogic.com/operations.html) for the
rule format.

## Custom Operations

Applications can add domain-specific operators. Custom operations receive
ArduinoJson views and return an owning document:

```cpp
JsonLogic::GetInstance()->AddOperation(
    "average",
    [](json_logic::JsonArrayView values, json_logic::JsonView) {
      Json result;
      result.set(
          (values[0].as<double>() + values[1].as<double>()) / 2.0);
      return result;
    });
```

Remove an operation with `RmOperation("average")`.

## Error Handling

On Arduino, invalid operations return a null `Json` result and store a message
in `GetLastError()`. Check `HasError()` after each top-level `Apply()` call.

On desktop builds with C++ exceptions enabled, invalid operations throw
`json_logic::JsonLogicException`.

## Handling Untrusted Rules

JsonLogic is data, not arbitrary native code, but user-provided rules still
need application-level limits:

- accept only known action identifiers and dispatch them in firmware
- limit input size and nesting depth before parsing
- authenticate rules received over a network
- avoid exposing custom operations that perform unrestricted side effects
- test memory use with the largest rules and data expected on the device

## Desktop CMake

CMake first looks for an installed ArduinoJson package. If none is found, it
downloads ArduinoJson 7.4.3 with `FetchContent`; no dependency source is
vendored in this repository.

```sh
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
```

Use the library from another CMake project:

```cmake
add_subdirectory(lib/json-logic-cpp)
target_link_libraries(my_app PRIVATE jsonlogic::jsonlogic)
```

## License

MIT
