Smart home devices represent a transformative paradigm in new and old homes, integrating advanced, low power smart technologies to enhance convenience, electricity usage, and security. But with current state of such devices it's hard to measure devices that are not connected through plugs or measure whole mains loops, i.e for lighting in a room or kitchen appliances like stove. Touching anything in such circuits is both unsafe and pretty much illegal in most countries in the world without having electrical license.
This project aims to create such power meter that can measure power in a non invasive way in circuits that are inaccessible by other means, like smart plugs. Also, main feature of this project is to use the current sensor (current transformer) as both the sensor, but also a power source making this project wireless and battery less.
Theory of operationMeasurement of power will be performed using nRF7002 DK connected to a current transformer through signal conditioning circuits. The current transformer will also act as a sole power source for the circuit. It will be used to charge the supercapacitor that will act as low power battery.
The project will have four main states. In the first state, when the circuit is not charged enough, the MCU will be disconnected and all the power will be delivered to the supercap.
Second state occurs when the supercapacitor gets charged enough. In this state the MCU is powered and the power gets cut from the charging circuit and is rerouted to burden circuit, in which the power is dissipated through the burden resistor to protect the current transformer from frying and also to perform current measurements through ADC conditioning and MCU.
Third and fourth states are basically copies of previous states, but the mains have too low load to actively power the device. In such case the MCU will keep reporting until supercap voltage goes below 2V.
The circuit is the main focus of this project. It can be divided into three different sub-circuits: burden circuit, charge circuit and a logic circuit, which toggles between two previously mentioned.
Burden circuit
Burden circuit act as a path of lowest resistance and consists of two separate pair of N-FET transistors connected to a resistor with a small resistance. Each pair is used to force the ac current from current transformer onto the burden resistor.
The first one is controlled by charge control circuit and switches from charge state to burden as a form to protection for DC/DC converter and a supercap in the moment when the voltage on supercap exceeds given limit. This is necessary as the current transformer is a current source. With voltage source (i.e some battery) it's easy to disconnect it from the circuit as a disconnected battery just won't generate any current on it's terminals. In case of current source, it is necessary to connect it's terminals to some sort of load. Otherwise, the current source will generate the current without any path of escape, which will greatly increase the voltage, which can cause the source to burn itself. In this circuit the burden resistor R1 act as this load, when the supercapacitor is charged.
The second one is controlled via nRF7002 DK. The MCU can omit the charge logic circuit and force the state of the charge controller from charging to burden for measurement purposes.
Burden current measurement
When the MCU switches the burden circuit on, it's done for measurement purposes. Given that my project is constrained for max 16A, the 100A/5A CT used in the project will give max of 800mA on the output terminals. With 0.1 Ohm resistor used as a burden it will give a max of 80mV peak to peak. This is not too big value considering the ADC measuring range of the DK. To increase the voltage output of the burden, I've used a simple differential amplifier, which will perform two functions. Firstly, of course it will increase the voltage from 80mV to rougly 3.2V (with a gain of 40). Secondly, The differential amplifier will output difference between two voltage points. In this case it's connected to both terminals of the burden resistor. This ensures that the resistance from switching N-FET's won't be included in the measurement, which means increased measurement precision.
The rectifier
Not much to write here. This is the first stage of charging circuit, that is used to rectify the output of the current transformer for further processing. It's worth noting that I've used Schottky diodes here for a bit lower voltage drop at this stage.
Protection circuits
Protection is the next stage of charging circuit. To keep the supercap within it's current / voltage specs, it's necessary to regulate the output of the current transformer in some way.
First is the voltage regulator. Given the low power that comes from the current transformer, it is safe to use simple Zener voltage divider circuit for this purpose.
Second is the current clamp. It is also pretty much generic circuit. R9 act as sense resistor. When the current exceeds 60mA, the remainder goes through Q3 to ground.
Output from these two circuits provides safe voltage and current that can be feed to the supercapacitor.
Control logic
Control logic is responsible for providing an over and undervoltage protection for the supercapacitor and DC/DC boost converter.
The first part of the controller are two P-FET transistors. One of them is disabled by default and can be enabled by controller when charging is required.
The second P-FET is controlled by MCU and enabled by default. It gets disabled by MCU everytime burden current is measured.
The R-78S3.3-0.1 boost converter is used to power up all of the logic controllers as well as the MCU. As described in datasheet the converter will turn on when supercap reaches voltage of around 0.6V. The 3.3V from this boost converter will also act as a signal for charging circuit, which will be described below.
Next part of the logic controller is the hysteresis controller, which will turn off when the voltage above 3V and turn on when the voltage goes below 2V.
This will allow to charge and discharge the cap in a safe voltage range.
XOR gate controls, whether capacitor should be charged or all the power should go to burden circuit.
The logic for it looks like this:
Lockout circuit basically cuts off the power to the MCU when voltage drops below acceptable level.
To make sure the control circuit works, I've checked it with falstad circuit simulator
Supercapacitor
Supercapacitor module has really nothing that matters. It connects to a controlled and conditioned input from current transformer and acts as battery for the project.
The circuit combined
Here you can see all components stacked together in KiCad:
Due to my little experience with such analog circuits I've decided to make the prototype on simple Arduino compatible prototype shield, on which each of presented above modules is separated from others by goldpin connectors. This was proven useful during testing of each module as well as the whole circuit.
Fully assembled prototype on the nRF7002 DK can be seen below:
Here you can see the complete circuit with each module connected to each other forming the full circuit:
The code in this project is pretty simple. Basically I've followed official tutorial how to add new clusters to Matter application. For lower power usage I've also used this tutorial and setted up the Matter device as Sleepy End Device (SED). Also, for debugging purposes I've used Advanced Matter Kconfig options to use Matter shell and I've changed reaction to fabric removal to "CONFIG_CHIP_LAST_FABRIC_REMOVED_ERASE_AND_PAIRING_START"
For zap tool configuration, the only thing worth noting is the measurement cluster, which is Home Automation -> Electrical Measurement:
For measurement types I've selected
- AC frequency (+ min / max)
- RMS voltage (+ min / max)
- RMS current (+ min / max)
- Active power (+ min / max)
Divisors for power and current were set to 1000.
I've also added Power Source cluster to report the capacitor voltage as a Battery Voltage.
Considering that the template application with above tutorials is sufficient for a simple sensor device, the only bits that are important in my application are the adc readings for burden and cap as well as the conversions to voltage, amperes and "battery" (capacitor) percent.
Burden voltage is measured in the following way:
Measurement ReadBurdenVoltage()
{
static int16_t buffer[1];
static adc_sequence seq = { .channels = BIT(burden_cfg_dt.channel_id),
.buffer = buffer,
.buffer_size = sizeof(buffer),
.resolution = ADC_RESOLUTION };
static int32_t adcVRef = adc_ref_internal(adc_dev);
Measurement res;
burden::SetMeasurementMode();
int err = adc_read(adc_dev, &seq);
if (err) {
LOG_WRN("Failed to read burden ADC");
burden::SetChargingMode();
res.success = false;
return res;
}
int32_t mV = buffer[0];
err = adc_raw_to_millivolts(adcVRef, burden_cfg_dt.gain, ADC_RESOLUTION, &mV);
if (err) {
LOG_WRN("Failed to convert burden reading to mV");
burden::SetChargingMode();
res.success = false;
return res;
}
burden::SetChargingMode();
res.value = mV;
res.success = true;
return res;
}
SetMeasurementMode and SetChargingMode are just wrappers for simple GPIO toggles.
Cap voltage is measured in a similar way:
Measurement ReadCapVoltage()
{
static int16_t buffer[1];
static adc_sequence seq = { .channels = BIT(battery_cfg_dt.channel_id),
.buffer = buffer,
.buffer_size = sizeof(buffer),
.resolution = ADC_RESOLUTION };
static int32_t adcVRef = adc_ref_internal(adc_dev);
Measurement res;
int err = adc_read(adc_dev, &seq);
if (err) {
LOG_WRN("Failed to read cap ADC");
res.success = false;
return res;
}
int32_t mV = buffer[0];
err = adc_raw_to_millivolts(adcVRef, battery_cfg_dt.gain, ADC_RESOLUTION, &mV);
if (err) {
LOG_WRN("Failed to convert cap reading to mV");
res.success = false;
return res;
}
res.value = mV;
res.success = true;
return res;
}
And converted to percent using:
int32_t ConvertBatteryVoltageToPercent(int32_t mV)
{
int32_t res = (100 * (mV - MIN_BATTERY_VOLTAGE)) / MAX_BATTERY_VOLTAGE;
if (res < 0) {
res = 0;
}
if (res > 100) {
res = 100;
}
return res;
}
Reading are setted every 20ms:
void AppTask::SensorMeasureHandler(const AppEvent &)
{
constexpr float SQRT_2 = 1.41421356237;
adc::Measurement currMeas = adc::ReadBurdenVoltage();
float current = map(currMeas.value, MIN_BURDEN_VOLTAGE, MAX_BURDEN_VOLTAGE, MIN_CUR R, MAX_CURR);
if (current < 0) {
current = 0;
}
current /= 1000; // To amps
if (currMeas.success) {
sRMSCurrent.addSample(current);
}
chip::app::Clusters::ElectricalMeasurement::Attributes::AcFrequency::Set(ENDPOINT_ID, MAINS_FREQUENCY);
float v = MAINS_VOLTAGE / SQRT_2;
chip::app::Clusters::ElectricalMeasurement::Attributes::RmsVoltage::Set(ENDPOINT_ID, v);
if (sRMSCurrent.ready() && currMeas.success) {
chip::app::Clusters::ElectricalMeasurement::Attributes::RmsCurrent::Set(
ENDPOINT_ID, sRMSCurrent.read() * 1000); // To mA again
chip::app::Clusters::ElectricalMeasurement::Attributes::ActivePower::Set(ENDPOINT_ID, current * MAINS_VOLTAGE);
}
adc::Measurement batMeas = adc::ReadCapVoltage();
int32_t bat = batMeas.value;
if (bat < 0) {
bat = 0;
}
if (batMeas.success) {
chip::app::Clusters::PowerSource::Attributes::BatVoltage::Set(0, bat);
chip::app::Clusters::PowerSource::Attributes::BatPercentRemaining::Set(
0, ConvertBatteryVoltageToPercent(bat));
}
}
Regarding the voltage and frequency measurement, due to time constraints I had to use mocked value based on average voltage of my mains (230V, 50Hz). Given more time I had in mind to use wireless capacitive sensor based on "Non-Invasive Voltage Measurement Technique for Low Voltage AC Lines" [doi:10.1109/ICET51757.2021.9450978], but this is an idea for the future.
TestingFor testing I've assembled simple DIN stand with single AC phase, power connector and a switch:
Testing was performed using prj_release.conf with disabled logging and other debugging features.
For testing purposes I've used OpenThread Border Router installed on RaspberryPI 4 along with nRF dongle acting as Thread antenna.
For communicating with the sensor I've used CHIP tool.
For testing load I've used my knock off prusa printer:
In conclusion, the development of this project was a such learning experience for me and I consider it as a cool and innovative prototype with the potential to provide easy energy monitoring in high load circuits. However, it is crucial to acknowledge that the practicality of this solution is heavily dependent on the power load as extended periods of inactivity in such scenarios may lead to unavailability issues, as the device might struggle to harvest sufficient energy for sustained operation.
I think that the usability of this device can be further improved as some of it's problems came from my lack of experience with such circuits as well as choice of some components. In example the current transformer used in the project is rated for max of 100A, while my device was designed in max 16A circuits in mind.
Overall this project was a fun learning experience for me. I've learned a lot regarding op amps, current sources and Matter.
Comments