Skip to main content
Version: 1.0

TMCU

TMCU communication uses numbered datapoints to exchange data with an external microcontroller. Each datapoint has a unique ID and data type.

Getting the TMCU Handle

const tmcuHandle = TMCU.get();

Reading Datapoints

Get a handle to a datapoint to read its current value and listen for changes:

const dp = tmcuHandle.getDatapoint(1);

if (dp) {
console.log('Current value:', dp.v);
dp.on('change', (res) => {
console.log('New value:', res.v);
});
}

Writing Datapoints

Send values to the hardware:

tmcuHandle.writeDatapoint(dpId, dataType, value);

Parameters:

  • dpId — Datapoint ID number
  • dataType — Data type constant:
    • TMCU.DT_BOOL — Boolean
    • TMCU.DT_INT — Signed 32-bit integer
    • TMCU.DT_ENUM — Enumeration (integer index)
    • TMCU.DT_RAW — Raw binary data
  • value — Value to send

Example:

tmcuHandle.writeDatapoint(1, TMCU.DT_BOOL, true);
tmcuHandle.writeDatapoint(2, TMCU.DT_INT, 100);

Bidirectional Synchronization Pattern

The core pattern for synchronizing hardware with virtual components:

Device to App

Listen for hardware changes and update the virtual component. Read the current value on startup, then subscribe to future changes:

const DP_STATE = 1;
const stateHandle = Service.getVCHandle('state');
const tmcuHandle = TMCU.get();

const dpState = tmcuHandle.getDatapoint(DP_STATE);
if (dpState) {
// Push initial value
if (dpState.v !== stateHandle.getValue()) {
stateHandle.setValue(dpState.v);
}
// Prevent update loop: only update if value actually changed
dpState.on('change', (res) => {
if (res.v !== stateHandle.getValue()) {
stateHandle.setValue(res.v);
}
});
}

App to Device

Listen for virtual component changes (user interactions) and write to hardware:

stateHandle.on('change', ({ value }) => {
tmcuHandle.writeDatapoint(DP_STATE, TMCU.DT_BOOL, value);
});

TMCU Examples

Simple Boolean Sync

For on/off controls:

const DP_STATE = 1;
const tmcuHandle = TMCU.get();
const stateHandle = Service.getVCHandle('state');

// Device to app
const dpState = tmcuHandle.getDatapoint(DP_STATE);
if (dpState) {
if (dpState.v !== stateHandle.getValue()) {
stateHandle.setValue(dpState.v);
}
dpState.on('change', (res) => {
if (res.v !== stateHandle.getValue()) {
stateHandle.setValue(res.v);
}
});
}

// App to device
stateHandle.on('change', ({ value }) => {
tmcuHandle.writeDatapoint(DP_STATE, TMCU.DT_BOOL, value);
});

Number with Transformation

For values that need scaling or unit conversion:

const DP_BRIGHTNESS = 2;
const tmcuHandle = TMCU.get();
const brightnessHandle = Service.getVCHandle('brightness');

// Hardware: 0-255, Component: 0-100%
const syncBrightness = (raw: unknown) => {
if (typeof raw !== 'number') return;
const percent = Math.round((raw / 255) * 100);
if (percent === brightnessHandle.getValue()) return;
brightnessHandle.setValue(percent);
};

// Device to app
const dpBrightness = tmcuHandle.getDatapoint(DP_BRIGHTNESS);
if (dpBrightness) {
syncBrightness(dpBrightness.v);
dpBrightness.on('change', (res) => syncBrightness(res.v));
}

// App to device
brightnessHandle.on('change', ({ value }) => {
const hwValue = Math.round((value / 100) * 255);
tmcuHandle.writeDatapoint(DP_BRIGHTNESS, TMCU.DT_INT, hwValue);
});

Read-Only Sensor

For sensors and status that users cannot change:

const DP_TEMP = 3;
const tmcuHandle = TMCU.get();
const temperatureHandle = Service.getVCHandle('temperature');

// Only device to app, no write listener
const syncTemp = (raw: unknown) => {
if (typeof raw !== 'number') return;
const temp = raw / 10; // Hardware reports as integer tenths
if (temp === temperatureHandle.getValue()) return;
temperatureHandle.setValue(temp);
};

const dpTemp = tmcuHandle.getDatapoint(DP_TEMP);
if (dpTemp) {
syncTemp(dpTemp.v);
dpTemp.on('change', (res) => syncTemp(res.v));
}

Enum/Mode Selection

For predefined options like heat/cool/off:

const DP_MODE = 2;
const MODES = ['off', 'heat', 'cool'];
const tmcuHandle = TMCU.get();
const modeHandle = Service.getVCHandle('mode');

// Device to app: hardware sends index, we map to string
const syncMode = (index: number) => {
const mode = MODES[index];
if (mode === modeHandle.getValue()) return;
modeHandle.setValue(mode);
};

const dpMode = tmcuHandle.getDatapoint(DP_MODE);
if (dpMode) {
syncMode(dpMode.v);
dpMode.on('change', (res) => syncMode(res.v));
}

// App to device: user selects string, we map to index
modeHandle.on('change', ({ value }) => {
const index = MODES.indexOf(value);
tmcuHandle.writeDatapoint(DP_MODE, TMCU.DT_INT, index);
});

Multiple Components

Complex devices with many independent controls:

const DP_STATE = 1;
const DP_BRIGHTNESS = 2;
const DP_COLOR_TEMP = 3;

const tmcuHandle = TMCU.get();
const stateHandle = Service.getVCHandle('state');
const brightnessHandle = Service.getVCHandle('brightness');
const colorTempHandle = Service.getVCHandle('color_temperature');

// Sync state
const dpState = tmcuHandle.getDatapoint(DP_STATE);
if (dpState) {
if (dpState.v !== stateHandle.getValue()) {
stateHandle.setValue(dpState.v);
}
dpState.on('change', (res) => {
if (res.v !== stateHandle.getValue()) {
stateHandle.setValue(res.v);
}
});
}

stateHandle.on('change', ({ value }) => {
tmcuHandle.writeDatapoint(DP_STATE, TMCU.DT_BOOL, value);
});

// Sync brightness
const dpBrightness = tmcuHandle.getDatapoint(DP_BRIGHTNESS);
if (dpBrightness) {
if (typeof dpBrightness.v === 'number' && dpBrightness.v !== brightnessHandle.getValue()) {
brightnessHandle.setValue(dpBrightness.v);
}
dpBrightness.on('change', (res) => {
if (typeof res.v !== 'number') return;
if (res.v === brightnessHandle.getValue()) return;
brightnessHandle.setValue(res.v);
});
}

brightnessHandle.on('change', ({ value }) => {
tmcuHandle.writeDatapoint(DP_BRIGHTNESS, TMCU.DT_INT, value);
});

// Sync color temperature
const dpColorTemp = tmcuHandle.getDatapoint(DP_COLOR_TEMP);
if (dpColorTemp) {
if (typeof dpColorTemp.v === 'number' && dpColorTemp.v !== colorTempHandle.getValue()) {
colorTempHandle.setValue(dpColorTemp.v);
}
dpColorTemp.on('change', (res) => {
if (typeof res.v !== 'number') return;
if (res.v === colorTempHandle.getValue()) return;
colorTempHandle.setValue(res.v);
});
}

colorTempHandle.on('change', ({ value }) => {
tmcuHandle.writeDatapoint(DP_COLOR_TEMP, TMCU.DT_INT, value);
});