asopi tech
asopi techIndie Developer

Asopitech With · Smartphone HEMS

Nature Remo E2 with Alopex Skulk

Nature Remo E2 is a smartphone-based home energy management system (HEMS) that shows a solar home's generation, consumption, and power bought and sold in real time on a phone. What would it look like built on Alopex Skulk?

Updated: Oct 12, 2026

What the service does

Nature Remo E2 is a smartphone HEMS that connects to the smart meter, solar panels and home batteries, and shows generation, consumption, and power bought and sold on a phone. The app also controls home batteries and heat-pump water heaters. The data is consumption and export time series.

Where the data lives

  • Skulk time series: consumption, imports and exports are appended to Skulk, tagged by home and measure.
  • Time buckets: daily, weekly and monthly totals and peaks come from time-bucketed aggregation.
  • PromQL: comparisons with yesterday or last month are PromQL queries.

Reading the smart meter and writing the values are app code.

Deployment

Skulk is embedded in the device in the home and in the app. The home’s power records stay in the home, and records from many homes are gathered by a Skulk cluster on the same engine.

Why Alopex Skulk fits

Energy monitoring is about comparing time series across periods. Skulk handles ingestion, time buckets and PromQL inside the device, and keeps the home’s power records in the home.

See it in code

Power readings are ingested into Skulk with Line Protocol and read back. Just the core (Rust).

use alopex_skulk::ingest::line_protocol::LineProtocolDecoder;
use alopex_skulk::ingest::{IngestLimits, Ingestor};
use alopex_skulk::model::FieldValue;
use alopex_skulk::store::recovery::{RecoveryConfig, RecoveryStore};

fn main() -> alopex_skulk::Result<()> {
    std::fs::create_dir_all("remo-data").unwrap();
    let store = RecoveryStore::open("remo-data", RecoveryConfig::default())?;
    let limits = IngestLimits::default();
    let mut ingestor = Ingestor::new(store, limits);

    // 消費電力(W)を、家のタグ付きで取り込む(measurement,tag field timestamp[ns])
    let base: i64 = 7_200_000_000_000;
    let now = base + 300_000_000_000;
    for (i, watts) in [320.0, 450.0, 1200.0].iter().enumerate() {
        let ts = base + (i as i64) * 60_000_000_000;
        let line = format!("power,home=main watts={watts} {ts}");
        let batch = LineProtocolDecoder::new(limits).decode(line.as_bytes(), now)?;
        assert_eq!(ingestor.ingest(batch, now)?.accepted_count(), 1);
    }
    ingestor.sink_mut().flush_all()?;

    // 取り込んだ消費電力を読み出す
    for row in &ingestor.sink().read_measurement("power")? {
        if let Some(FieldValue::Float(watts)) = row.row().field("watts") {
            println!("t={} watts={watts}", row.row().timestamp());
        }
    }
    Ok(())
}

Ingest is durable when ingest() returns. Daily, weekly and monthly totals and day-over-day comparisons come from Skulk’s time-bucket aggregation / PromQL.

Alopex Skulk runs time buckets and PromQL inside the device. Try building home energy monitoring with it.