I2CDevices: Add support for the INA219 energy meter
parent
74290ca1a3
commit
ce599e43c9
|
|
@ -99,3 +99,26 @@ more than 16 channels are required.
|
|||
|
||||
Additional information ca be found at the devices users guide at
|
||||
[https://www.alchemy-power.com/wp-content/uploads/2017/03/Pi-16ADC-User-Guide.pdf](https://www.alchemy-power.com/wp-content/uploads/2017/03/Pi-16ADC-User-Guide.pdf).
|
||||
|
||||
## INA219
|
||||
|
||||
The INA219 is a voltage/current meter by Texas Instruments.
|
||||
|
||||
### Usage
|
||||
|
||||
In order to use this device within nymea, it needs to be connected to the I²C bus. At least SDA,
|
||||
SCL, GND and VDD must be connected. Normally the device comes with a 0.1 Ohm shunt resistor. If
|
||||
replacing the shunt resistor on the device with something else, the according value needs to be
|
||||
given during the setup in nymea.
|
||||
|
||||
The measured input value will be a floating point value from 0 to 1, depending on the selected input gain.
|
||||
For instance, if the selected input gain is 4.096V, a voltage of 0V will be indicated in nymea as
|
||||
0 while an input voltage of 4.096V will be represented as 1.
|
||||
|
||||
Setup can be done by performing a discovery for it in nymea. Please verify that the found results
|
||||
are matching with the address configuration of the device. If the address selector pins are unmodified,
|
||||
the I²C address will be 64 (0x48). It can be configured to another I²C address by bridging the addrss
|
||||
selector pins on the device. The INA219 has selectable addresses from 0x40 tox 0x4A.
|
||||
|
||||
The device will represent itself as energy meter in nymea and if used, for example in a caravan, it ca
|
||||
cater as the root meter for the caravans energy system.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
include(../plugins.pri)
|
||||
|
||||
HEADERS += \
|
||||
ina219.h \
|
||||
integrationplugini2cdevices.h \
|
||||
ads1115channel.h \
|
||||
pi16adcchannel.h
|
||||
|
||||
|
||||
SOURCES += \
|
||||
ina219.cpp \
|
||||
integrationplugini2cdevices.cpp \
|
||||
ads1115channel.cpp \
|
||||
pi16adcchannel.cpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,187 @@
|
|||
#include "ina219.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <QtDebug>
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#define INA219_REGISTER_CONFIGURATION 0x00
|
||||
#define INA219_REGISTER_SHUNT_VOLTAGE 0x01
|
||||
#define INA219_REGISTER_BUS_VOLTAGE 0x02
|
||||
#define INA219_REGISTER_POWER 0x03
|
||||
#define INA219_REGISTER_CURRENT 0x04
|
||||
#define INA219_REGISTER_CALIBRATION 0x05
|
||||
|
||||
#define INA219_ADDRESS 0x80
|
||||
#define INA219_READ 0x01
|
||||
|
||||
#define SHUNT_MILLIVOLTS_LSB 0.01 //# 10uV
|
||||
#define BUS_MILLIVOLTS_LSB 4 // 4mV
|
||||
#define CALIBRATION_FACTOR 0.04096
|
||||
#define MAX_CALIBRATION_VALUE 0xFFFE // Max value supported (65534 decimal)
|
||||
// # In the spec (p17) the current LSB factor for the minimum LSB is
|
||||
// # documented as 32767, but a larger value (100.1% of 32767) is used
|
||||
// # to guarantee that current overflow can always be detected.
|
||||
#define CURRENT_LSB_FACTOR 32800
|
||||
|
||||
#define OVERFLOW_VALUE 1
|
||||
|
||||
#define INA219_CONFIG_BIT_RST 15
|
||||
#define INA219_CONFIG_BIT_BRNG 13
|
||||
#define INA219_CONFIG_BIT_PG1 12
|
||||
#define INA219_CONFIG_BIT_PG0 11
|
||||
#define INA219_CONFIG_BIT_BADC4 10
|
||||
#define INA219_CONFIG_BIT_BADC3 9
|
||||
#define INA219_CONFIG_BIT_BADC2 8
|
||||
#define INA219_CONFIG_BIT_BADC1 7
|
||||
#define INA219_CONFIG_BIT_SADC4 6
|
||||
#define INA219_CONFIG_BIT_SADC3 5
|
||||
#define INA219_CONFIG_BIT_SADC2 4
|
||||
#define INA219_CONFIG_BIT_SADC1 3
|
||||
#define INA219_CONFIG_BIT_MODE3 2
|
||||
#define INA219_CONFIG_BIT_MODE2 1
|
||||
#define INA219_CONFIG_BIT_MODE1 0
|
||||
|
||||
|
||||
Ina219::Ina219(const QString &portName, int address, double shuntOhms, VoltageRange voltageRange, QObject *parent):
|
||||
I2CDevice(portName, address, parent),
|
||||
m_shuntOhms(shuntOhms),
|
||||
m_voltageRange(voltageRange)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Ina219::writeData(int fileDescriptor, const QByteArray &data)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
|
||||
char buf[3] = {0};
|
||||
|
||||
// Calibration
|
||||
double gain;
|
||||
switch (m_gainVolts) {
|
||||
case GainVolts032:
|
||||
gain = 0.32;
|
||||
break;
|
||||
case GainVolts016:
|
||||
gain = 0.16;
|
||||
break;
|
||||
case GainVolts008:
|
||||
gain = 0.08;
|
||||
break;
|
||||
case GainVolts004:
|
||||
default:
|
||||
gain = 0.04;
|
||||
break;
|
||||
}
|
||||
|
||||
double maxPossibleAmps = gain / m_shuntOhms;
|
||||
m_currentLSB = maxPossibleAmps / CURRENT_LSB_FACTOR;
|
||||
|
||||
quint16 calibration = CALIBRATION_FACTOR / (m_currentLSB * m_shuntOhms);
|
||||
buf[0] = INA219_REGISTER_CALIBRATION;
|
||||
buf[1] = calibration >> 8;
|
||||
buf[2] = calibration & 0xFF;
|
||||
qCDebug(dcI2cDevices()) << "INA219 writing calibration:" << QString::number(calibration, 16) << QByteArray(buf, 3).toHex();
|
||||
int ret = write(fileDescriptor, buf, 3);
|
||||
if (ret != 3) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to write calibration to INA219.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configuration
|
||||
quint16 configuration = m_voltageRange << INA219_CONFIG_BIT_BRNG;
|
||||
configuration |= m_gainVolts << INA219_CONFIG_BIT_PG0;
|
||||
configuration |= m_busADC << INA219_CONFIG_BIT_BADC1;
|
||||
configuration |= m_shuntADC << INA219_CONFIG_BIT_SADC1;
|
||||
configuration |= m_operationMode;
|
||||
buf[0] = INA219_REGISTER_CONFIGURATION;
|
||||
buf[1] = configuration >> 8;
|
||||
buf[2] = configuration & 0xFF;
|
||||
qCDebug(dcI2cDevices()) << "INA219 writing configuration:" << QString::number(configuration, 16) << QByteArray(buf, 3).toHex();
|
||||
ret = write(fileDescriptor, buf, 3);
|
||||
if (ret != 3) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to write configuration to INA219.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QByteArray Ina219::readData(int fileDescriptor)
|
||||
{
|
||||
char buf[2] = {0};
|
||||
|
||||
buf[0] = INA219_REGISTER_SHUNT_VOLTAGE;
|
||||
int ret = write(fileDescriptor, buf, 1);
|
||||
if (ret != 1) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to select shunt voltage register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
ret = read(fileDescriptor, buf, 2);
|
||||
if (ret != 2) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to read shunt voltage register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
int shuntVoltageRaw = ((buf[0] << 8) | buf[1]);
|
||||
double shuntVoltage = shuntVoltageRaw * SHUNT_MILLIVOLTS_LSB / 1000;
|
||||
|
||||
|
||||
buf[0] = INA219_REGISTER_BUS_VOLTAGE;
|
||||
ret = write(fileDescriptor, buf, 1);
|
||||
if (ret != 1) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to select bus voltage register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
ret = read(fileDescriptor, buf, 2);
|
||||
if (ret != 2) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to read bus voltage register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
int busVoltageRaw = ((buf[0] << 8) | buf[1]);
|
||||
bool overflow = (busVoltageRaw & OVERFLOW_VALUE) == 1;
|
||||
busVoltageRaw = busVoltageRaw >> 3; // Registers are not right_aligned
|
||||
double busVoltage = 1.0 * busVoltageRaw * BUS_MILLIVOLTS_LSB / 1000;
|
||||
|
||||
buf[0] = INA219_REGISTER_POWER;
|
||||
ret = write(fileDescriptor, buf, 1);
|
||||
if (ret != 1) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to select power register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
ret = read(fileDescriptor, buf, 2);
|
||||
if (ret != 2) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to read power register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
int powerRaw = ((buf[0] << 8) | buf[1]);
|
||||
double powerLSB = m_currentLSB * 20;
|
||||
double power = powerRaw * powerLSB;
|
||||
|
||||
buf[0] = INA219_REGISTER_CURRENT;
|
||||
ret = write(fileDescriptor, buf, 1);
|
||||
if (ret != 1) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to select current register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
ret = read(fileDescriptor, buf, 2);
|
||||
if (ret != 2) {
|
||||
qCWarning(dcI2cDevices()) << "Failed to read current register on INA219";
|
||||
return QByteArray();
|
||||
}
|
||||
int currentRaw = ((buf[0] << 8) | buf[1]);
|
||||
double current = 1.0 * currentRaw * m_currentLSB;
|
||||
|
||||
qCDebug(dcI2cDevices()).nospace().noquote() << "INA219 Shunt voltage: " << shuntVoltage << "mV, Bus voltage: " << busVoltage << "V, Power: " << power << "W, Current: " << current << "A, Overflow: " << overflow;
|
||||
|
||||
QVariantMap readings;
|
||||
readings.insert("shuntVoltage", shuntVoltage);
|
||||
readings.insert("busVoltage", busVoltage);
|
||||
readings.insert("power", power);
|
||||
readings.insert("current", current);
|
||||
readings.insert("overflow", overflow);
|
||||
return QJsonDocument::fromVariant(readings).toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#ifndef INA219_H
|
||||
#define INA219_H
|
||||
|
||||
#include <QObject>
|
||||
#include <hardware/i2c/i2cdevice.h>
|
||||
|
||||
class Ina219 : public I2CDevice
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum VoltageRange {
|
||||
VoltageRange16 = 0,
|
||||
VoltageRange32 = 1
|
||||
};
|
||||
Q_ENUM(VoltageRange)
|
||||
|
||||
enum GainVolts {
|
||||
GainVolts004 = 0,
|
||||
GainVolts008 = 1,
|
||||
GainVolts016 = 2,
|
||||
GainVolts032 = 3,
|
||||
};
|
||||
Q_ENUM(GainVolts)
|
||||
|
||||
enum ADCBits {
|
||||
ADCBits9 = 0,
|
||||
ADCBits10 = 1,
|
||||
ADCBits11 = 2,
|
||||
ADCBits12 = 3
|
||||
};
|
||||
Q_ENUM(ADCBits)
|
||||
|
||||
enum OperationMode {
|
||||
OperationModePowerDown = 0,
|
||||
OperationModeShuntVoltageTriggered = 1,
|
||||
OperationModeBusVoltageTriggered = 2,
|
||||
OperationModeShuntAndBusTriggered = 3,
|
||||
OperationModeADCOff = 4,
|
||||
OperationModeShuntVoltageContinuous = 5,
|
||||
OperationModeBusVoltageContinuous = 6,
|
||||
OperationModeShuntAndBusContinuous = 7
|
||||
};
|
||||
Q_ENUM(OperationMode)
|
||||
|
||||
explicit Ina219(const QString &portName, int address, double shuntOhms, VoltageRange voltageRange, QObject *parent = nullptr);
|
||||
|
||||
bool writeData(int fileDescriptor, const QByteArray &data) override;
|
||||
QByteArray readData(int fileDescriptor) override;
|
||||
|
||||
signals:
|
||||
void measurementAvailable();
|
||||
|
||||
private:
|
||||
double m_shuntOhms = 0.1;
|
||||
VoltageRange m_voltageRange = VoltageRange32;
|
||||
GainVolts m_gainVolts = GainVolts004;
|
||||
ADCBits m_busADC = ADCBits12;
|
||||
ADCBits m_shuntADC = ADCBits12;
|
||||
OperationMode m_operationMode = OperationModeShuntAndBusContinuous;
|
||||
|
||||
double m_currentLSB = 0;
|
||||
};
|
||||
|
||||
#endif // INA219_H
|
||||
|
|
@ -33,10 +33,12 @@
|
|||
|
||||
#include "pi16adcchannel.h"
|
||||
#include "ads1115channel.h"
|
||||
#include "ina219.h"
|
||||
|
||||
#include <hardware/i2c/i2cmanager.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
|
||||
IntegrationPluginI2CDevices::IntegrationPluginI2CDevices(): IntegrationPlugin()
|
||||
{
|
||||
|
|
@ -107,7 +109,7 @@ void IntegrationPluginI2CDevices::discoverThings(ThingDiscoveryInfo *info)
|
|||
}
|
||||
|
||||
if (info->thingClassId() == ads1115ThingClassId) {
|
||||
// The ADS1115 has selectable addresses from 0x48 to 0x51
|
||||
// The ADS1115 has selectable addresses from 0x48 to 0x4B
|
||||
if (scanResult.address >= 0x48 && scanResult.address <= 0x4B) {
|
||||
ThingDescriptor descriptor(ads1115ThingClassId, "ADS1113/ADS1114/ADS1115", QString("%1: 0x%2").arg(scanResult.portName).arg(scanResult.address, 0, 16));
|
||||
ParamList params;
|
||||
|
|
@ -117,6 +119,18 @@ void IntegrationPluginI2CDevices::discoverThings(ThingDiscoveryInfo *info)
|
|||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
if (info->thingClassId() == ina219ThingClassId) {
|
||||
// The INA219 has selectable addresses from 0x040 tox 0x4A
|
||||
if (scanResult.address >= 0x40 && scanResult.address <= 0x4A) {
|
||||
ThingDescriptor descriptor(ina219ThingClassId, "INA219", QString("%1: 0x%2").arg(scanResult.portName).arg(scanResult.address, 0, 16));
|
||||
ParamList params;
|
||||
params << Param(ina219ThingI2cPortParamTypeId, scanResult.portName);
|
||||
params << Param(ina219ThingI2cAddressParamTypeId, scanResult.address);
|
||||
descriptor.setParams(params);
|
||||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
|
|
@ -200,6 +214,56 @@ void IntegrationPluginI2CDevices::setupThing(ThingSetupInfo *info)
|
|||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
if (info->thing()->thingClassId() == ina219ThingClassId) {
|
||||
QString i2cPortName = info->thing()->paramValue(ina219ThingI2cPortParamTypeId).toString();
|
||||
int i2cAddress = info->thing()->paramValue(ina219ThingI2cAddressParamTypeId).toInt();
|
||||
double shuntOhms = info->thing()->paramValue(ina219ThingShuntOhmsParamTypeId).toDouble();
|
||||
Ina219::VoltageRange voltageRange = info->thing()->paramValue(ina219ThingVoltageRangeParamTypeId).toUInt() == 16 ? Ina219::VoltageRange16 : Ina219::VoltageRange32;
|
||||
|
||||
Ina219 *ina219 = new Ina219(i2cPortName, i2cAddress, shuntOhms, voltageRange, this);
|
||||
if (!hardwareManager()->i2cManager()->open(ina219)) {
|
||||
delete ina219;
|
||||
info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Failed to open I2C port."));
|
||||
return;
|
||||
}
|
||||
|
||||
Thing *thing = info->thing();
|
||||
connect(ina219, &Ina219::readingAvailable, thing, [thing](const QByteArray &data){
|
||||
QJsonParseError error;
|
||||
QVariantMap values = QJsonDocument::fromJson(data, &error).toVariant().toMap();
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qCWarning(dcI2cDevices()) << thing->name() << "Failed to read data from INA219";
|
||||
return;
|
||||
}
|
||||
double currentPower = values.value("power").toDouble();
|
||||
thing->setStateValue(ina219CurrentPowerStateTypeId, currentPower);
|
||||
thing->setStateValue(ina219VoltagePhaseAStateTypeId, values.value("busVoltage").toDouble());
|
||||
thing->setStateValue(ina219CurrentPhaseAStateTypeId, values.value("current").toDouble());
|
||||
thing->setStateValue(ina219OverflowStateTypeId, values.value("overflow").toBool());
|
||||
|
||||
// Calculate an estimate of totalEnergyConsumed
|
||||
QDateTime lastUpdate = thing->property("lastUpdate").toDateTime();
|
||||
if (lastUpdate.isNull()) {
|
||||
lastUpdate = QDateTime::currentDateTime();
|
||||
}
|
||||
double hoursPassed = lastUpdate.msecsTo(QDateTime::currentDateTime()) / 1000 / 60 / 60;
|
||||
if (currentPower >= 0) {
|
||||
double totalEnergyConsumed = thing->stateValue(ina219TotalEnergyConsumedStateTypeId).toDouble();
|
||||
totalEnergyConsumed += currentPower / 1000 * hoursPassed;
|
||||
thing->setStateValue(ina219TotalEnergyConsumedStateTypeId, totalEnergyConsumed);
|
||||
} else {
|
||||
double totalEnergyReturned = thing->stateValue(ina219TotalEnergyProducedStateTypeId).toDouble();
|
||||
totalEnergyReturned += -currentPower / 1000 * hoursPassed;
|
||||
thing->setStateValue(ina219TotalEnergyProducedStateTypeId, totalEnergyReturned);
|
||||
}
|
||||
});
|
||||
|
||||
hardwareManager()->i2cManager()->writeData(ina219, "init");
|
||||
hardwareManager()->i2cManager()->startReading(ina219, 5000);
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginI2CDevices::thingRemoved(Thing *thing)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include <integrations/integrationplugin.h>
|
||||
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
class I2CDevice;
|
||||
|
||||
class IntegrationPluginI2CDevices: public IntegrationPlugin
|
||||
|
|
|
|||
|
|
@ -449,6 +449,102 @@
|
|||
"defaultValue": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "95239915-fe8e-403f-b1b8-9132c4cbef3c",
|
||||
"name": "ina219",
|
||||
"displayName": "INA219",
|
||||
"createMethods": ["discovery"],
|
||||
"interfaces": ["energymeter"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "28ef56f1-8057-4ca5-879f-20914a63982a",
|
||||
"name": "i2cPort",
|
||||
"displayName": "I2C port",
|
||||
"type": "QString"
|
||||
},
|
||||
{
|
||||
"id": "380d18b4-551d-4b47-99e4-bfc231ff9d9d",
|
||||
"name": "i2cAddress",
|
||||
"displayName": "I2C address",
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
"id": "80b72157-24f9-4bb3-ab89-78feaf0248ff",
|
||||
"name": "shuntOhms",
|
||||
"displayName": "Shunt resistor",
|
||||
"type": "double",
|
||||
"unit": "Ohm",
|
||||
"minValue": 0,
|
||||
"maxValue": 1000000,
|
||||
"defaultValue": 0.1
|
||||
},
|
||||
{
|
||||
"id": "40b3d7da-908e-4b17-a483-28580b598c69",
|
||||
"name": "voltageRange",
|
||||
"displayName": "Voltage range",
|
||||
"type": "uint",
|
||||
"unit": "Volt",
|
||||
"allowedValues": [16, 32],
|
||||
"defaultValue": 16
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "49fdc415-f270-48ef-9b8f-1212d0cb39e4",
|
||||
"name": "currentPower",
|
||||
"displayName": "Current power",
|
||||
"displayNameEvent": "Current power changed",
|
||||
"type": "double",
|
||||
"unit": "Watt",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "64856549-f445-4c15-bdda-5a1513604a88",
|
||||
"name": "totalEnergyConsumed",
|
||||
"displayName": "Total consumed energy",
|
||||
"displayNameEvent": "Total consumed energy changed",
|
||||
"type": "double",
|
||||
"unit": "KiloWattHour",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "ff6461fb-ebbf-4acf-bcbb-8de2ddd3b15b",
|
||||
"name": "totalEnergyProduced",
|
||||
"displayName": "Total returned energy",
|
||||
"displayNameEvent": "Total returned energy changed",
|
||||
"type": "double",
|
||||
"unit": "KiloWattHour",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "2da9be93-85cd-4504-8ae8-91af351963a8",
|
||||
"name": "currentPhaseA",
|
||||
"displayName": "Current",
|
||||
"displayNameEvent": "Current changed",
|
||||
"type": "double",
|
||||
"unit": "Ampere",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "b4ea6bcb-39f6-45aa-893e-275cfbf0bcd3",
|
||||
"name": "voltagePhaseA",
|
||||
"displayName": "Voltage",
|
||||
"displayNameEvent": "Voltage changed",
|
||||
"type": "double",
|
||||
"unit": "Volt",
|
||||
"defaultValue": 0
|
||||
},
|
||||
{
|
||||
"id": "f31947cc-8c48-4bc3-b61b-01cfc7b472bf",
|
||||
"name": "overflow",
|
||||
"displayName": "Overflow",
|
||||
"displayNameEvent": "Overflow changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"cached": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue