tag: option unit

This commit is contained in:
fengzero
2026-03-26 08:42:24 +00:00
parent b8a9ce4b4e
commit ae4623ed7e
13 changed files with 152 additions and 34 deletions
+1
View File
@@ -59,6 +59,7 @@
#define NEU_TAG_META_LENGTH 20
#define NEU_TAG_META_SIZE 32
#define NEU_TAG_FORMAT_LENGTH 16
#define NEU_TAG_UNIT_LENGTH 16
#define NEU_LOG_LEVEL_DEBUG "debug"
#define NEU_LOG_LEVEL_INFO "info"
+5
View File
@@ -1470,6 +1470,11 @@ neu_tag_value_to_json_paginate(neu_resp_tag_value_meta_paginate_t *tag_value,
tag_json->datatag.bias = tag_value->datatag.bias;
tag_json->datatag.description = strdup(tag_value->datatag.description);
tag_json->datatag.option = tag_value->datatag.option;
if (tag_value->datatag.unit) {
tag_json->datatag.unit = strdup(tag_value->datatag.unit);
} else {
tag_json->datatag.unit = strdup("");
}
memcpy(tag_json->datatag.meta, tag_value->datatag.meta,
NEU_TAG_META_LENGTH);
+1
View File
@@ -93,6 +93,7 @@ typedef struct {
double decimal;
double bias;
char * description;
char * unit;
neu_datatag_addr_option_u option;
uint8_t meta[NEU_TAG_META_LENGTH];
uint8_t format[NEU_TAG_FORMAT_LENGTH];
+5
View File
@@ -0,0 +1,5 @@
BEGIN TRANSACTION;
alter TABLE tags add column unit TEXT NULL check(length(unit) <= 128);
COMMIT;
+17
View File
@@ -95,6 +95,11 @@ void handle_add_tags(nng_aio *aio)
} else {
cmd.tags[i].description = strdup("");
}
if (req->tags[i].unit == NULL) {
cmd.tags[i].unit = strdup("");
} else {
cmd.tags[i].unit = strdup(req->tags[i].unit);
}
}
int ret = neu_plugin_op(plugin, header, &cmd);
@@ -216,6 +221,12 @@ void handle_add_gtags(nng_aio *aio)
} else {
cmd.groups[i].tags[j].description = strdup("");
}
if (req->groups[i].tags[j].unit == NULL) {
cmd.groups[i].tags[j].unit = strdup("");
} else {
cmd.groups[i].tags[j].unit =
strdup(req->groups[i].tags[j].unit);
}
}
}
@@ -382,6 +393,11 @@ void handle_update_tags(nng_aio *aio)
} else {
cmd.tags[i].description = strdup("");
}
if (req->tags[i].unit == NULL) {
cmd.tags[i].unit = strdup("");
} else {
cmd.tags[i].unit = strdup(req->tags[i].unit);
}
}
ret = neu_plugin_op(plugin, header, &cmd);
@@ -529,6 +545,7 @@ void handle_get_tags_resp(nng_aio *aio, neu_resp_get_tag_t *tags)
tags_res.tags[index].decimal = tag->decimal;
tags_res.tags[index].bias = tag->bias;
tags_res.tags[index].t = NEU_JSON_UNDEFINE;
tags_res.tags[index].unit = tag->unit;
}
neu_json_encode_by_fn(&tags_res, neu_json_encode_get_tags_resp, &result);
+8
View File
@@ -894,6 +894,12 @@ void handle_read_paginate_resp(nng_aio * aio,
strdup(tag_value->datatag.address);
new_tag_value.datatag.description =
strdup(tag_value->datatag.description);
if (tag_value->datatag.unit) {
new_tag_value.datatag.unit =
strdup(tag_value->datatag.unit);
} else {
new_tag_value.datatag.unit = strdup("");
}
utarray_push_back(filtered_tags, &new_tag_value);
}
@@ -908,6 +914,7 @@ void handle_read_paginate_resp(nng_aio * aio,
free(orig_tag_value->datatag.name);
free(orig_tag_value->datatag.address);
free(orig_tag_value->datatag.description);
free(orig_tag_value->datatag.unit);
}
}
@@ -997,6 +1004,7 @@ void handle_read_paginate_resp(nng_aio * aio,
free(final_tag_value->datatag.name);
free(final_tag_value->datatag.address);
free(final_tag_value->datatag.description);
free(final_tag_value->datatag.unit);
}
}
+8
View File
@@ -40,6 +40,11 @@ static void tag_array_copy(void *_dst, const void *_src)
dst->address = strdup(src->address);
dst->name = strdup(src->name);
dst->description = strdup(src->description);
if (src->unit == NULL) {
dst->unit = strdup("");
} else {
dst->unit = strdup(src->unit);
}
memcpy(dst->format, src->format, sizeof(src->format));
dst->n_format = src->n_format;
@@ -53,6 +58,9 @@ static void tag_array_free(void *_elt)
free(elt->name);
free(elt->address);
free(elt->description);
if (elt->unit) {
free(elt->unit);
}
}
void neu_tag_format_str(const neu_datatag_t *tag, char *buf, int len)
+21 -16
View File
@@ -137,22 +137,26 @@ int neu_json_encode_read_paginate_resp(void *json_object, void *param)
tag_elems[7].t = NEU_JSON_DOUBLE;
tag_elems[7].v.val_double = p_tag->datatag.bias;
tag_elems[8].name = "unit";
tag_elems[8].t = NEU_JSON_STR;
tag_elems[8].v.val_str = p_tag->datatag.unit;
if (p_tag->error != 0) {
tag_elems[8].name = "error";
tag_elems[8].t = NEU_JSON_INT;
tag_elems[8].v.val_int = p_tag->error;
tag_elems[9].name = "error";
tag_elems[9].t = NEU_JSON_INT;
tag_elems[9].v.val_int = p_tag->error;
} else {
tag_elems[8].name = "value";
tag_elems[8].t = p_tag->t;
tag_elems[8].v = p_tag->value;
tag_elems[8].precision = p_tag->precision;
tag_elems[8].bias = p_tag->datatag.bias;
tag_elems[9].name = "value";
tag_elems[9].t = p_tag->t;
tag_elems[9].v = p_tag->value;
tag_elems[9].precision = p_tag->precision;
tag_elems[9].bias = p_tag->datatag.bias;
if (p_tag->t == NEU_JSON_FLOAT || p_tag->t == NEU_JSON_DOUBLE) {
if_precision = 1;
tag_elems[9].name = "transferPrecision";
tag_elems[9].t = NEU_JSON_INT;
tag_elems[9].v.val_int =
if_precision = 1;
tag_elems[10].name = "transferPrecision";
tag_elems[10].t = NEU_JSON_INT;
tag_elems[10].v.val_int =
p_tag->precision > 0 ? p_tag->precision : 1;
}
}
@@ -166,16 +170,17 @@ int neu_json_encode_read_paginate_resp(void *json_object, void *param)
neu_json_encode_field(attributes_object, &meta_elem, 1);
}
tag_elems[if_precision + 9].name = "attributes";
tag_elems[if_precision + 9].t = NEU_JSON_OBJECT;
tag_elems[if_precision + 9].v.val_object = attributes_object;
tag_elems[if_precision + 10].name = "attributes";
tag_elems[if_precision + 10].t = NEU_JSON_OBJECT;
tag_elems[if_precision + 10].v.val_object = attributes_object;
tag_array =
neu_json_encode_array(tag_array, tag_elems, 10 + if_precision);
neu_json_encode_array(tag_array, tag_elems, 11 + if_precision);
free(p_tag->datatag.name);
free(p_tag->datatag.address);
free(p_tag->datatag.description);
free(p_tag->datatag.unit);
p_tag++;
}
+12
View File
@@ -84,6 +84,11 @@ int neu_json_encode_tag(void *json_obj, void *param)
.t = tag->t,
.v = tag->value,
},
{
.name = "unit",
.t = NEU_JSON_STR,
.v.val_str = tag->unit,
},
};
ret = neu_json_encode_field(json_obj, tag_elems,
@@ -140,6 +145,11 @@ int neu_json_decode_tag_json(void *json_obj, neu_json_tag_t *tag_p)
.t = NEU_JSON_DOUBLE,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
{
.name = "unit",
.t = NEU_JSON_STR,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
};
int ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(tag_elems),
@@ -157,6 +167,7 @@ int neu_json_decode_tag_json(void *json_obj, neu_json_tag_t *tag_p)
.t = tag_elems[7].t,
.value = tag_elems[7].v,
.bias = tag_elems[8].v.val_double,
.unit = tag_elems[9].v.val_str,
};
if (0 != ret) {
@@ -180,6 +191,7 @@ void neu_json_decode_tag_fini(neu_json_tag_t *tag)
free(tag->name);
free(tag->address);
free(tag->description);
free(tag->unit);
if (NEU_JSON_STR == tag->t) {
free(tag->value.val_str);
}
+1
View File
@@ -42,6 +42,7 @@ typedef struct {
double bias;
neu_json_type_e t;
neu_json_value_u value;
char * unit;
} neu_json_tag_t;
int neu_json_encode_tag(void *json_obj, void *param);
+22 -14
View File
@@ -623,11 +623,11 @@ int neu_sqlite_persister_store_tag(neu_persister_t * self,
((neu_sqlite_persister_t *) self)->db,
"INSERT INTO tags ("
" driver_name, group_name, name, address, attribute,"
" precision, type, decimal, bias, description, value, format"
") VALUES (%Q, %Q, %Q, %Q, %i, %i, %i, %lf, %lf, %Q, %Q, %Q)",
" precision, type, decimal, bias, description, value, format, unit"
") VALUES (%Q, %Q, %Q, %Q, %i, %i, %i, %lf, %lf, %Q, %Q, %Q, %Q)",
driver_name, group_name, tag->name, tag->address, tag->attribute,
tag->precision, tag->type, tag->decimal, tag->bias, tag->description,
"", format_buf);
"", format_buf, tag->unit);
return rv;
}
@@ -706,6 +706,12 @@ static int put_tags(sqlite3 *db, const char *query, sqlite3_stmt *stmt,
return -1;
}
if (SQLITE_OK != sqlite3_bind_text(stmt, 13, tag->unit, -1, NULL)) {
nlog_error("bind `%s` with unit=`%s` fail: %s", query, tag->unit,
sqlite3_errmsg(db));
return -1;
}
if (SQLITE_DONE != sqlite3_step(stmt)) {
nlog_error("sqlite3_step fail: %s", sqlite3_errmsg(db));
return -1;
@@ -726,8 +732,8 @@ int neu_sqlite_persister_store_tags(neu_persister_t * self,
const char * query =
"INSERT INTO tags ("
" driver_name, group_name, name, address, attribute,"
" precision, type, decimal, bias, description, value, format"
") VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)";
" precision, type, decimal, bias, description, value, format, unit"
") VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13)";
if (SQLITE_OK != sqlite3_exec(persister->db, "BEGIN", NULL, NULL, NULL)) {
nlog_error("begin transaction fail: %s", sqlite3_errmsg(persister->db));
@@ -788,6 +794,7 @@ static int collect_tag_info(sqlite3_stmt *stmt, UT_array **tags)
.decimal = sqlite3_column_double(stmt, 5),
.bias = sqlite3_column_double(stmt, 6),
.description = (char *) sqlite3_column_text(stmt, 7),
.unit = (char *) sqlite3_column_text(stmt, 10),
};
tag.n_format = neu_format_from_str(format, tag.format);
@@ -812,7 +819,7 @@ int neu_sqlite_persister_load_tags(neu_persister_t *self,
sqlite3_stmt *stmt = NULL;
const char * query = "SELECT name, address, attribute, precision, type, "
"decimal, bias, description, value, format "
"decimal, bias, description, value, format, unit "
"FROM tags WHERE driver_name=? AND group_name=? "
"ORDER BY rowid ASC";
@@ -856,14 +863,15 @@ int neu_sqlite_persister_update_tag(neu_persister_t * self,
const char * group_name,
const neu_datatag_t *tag)
{
int rv = execute_sql(((neu_sqlite_persister_t *) self)->db,
"UPDATE tags SET"
" address=%Q, attribute=%i, precision=%i, type=%i,"
" decimal=%lf, bias=%lf, description=%Q, value=%Q "
"WHERE driver_name=%Q AND group_name=%Q AND name=%Q",
tag->address, tag->attribute, tag->precision,
tag->type, tag->decimal, tag->bias, tag->description,
"", driver_name, group_name, tag->name);
int rv =
execute_sql(((neu_sqlite_persister_t *) self)->db,
"UPDATE tags SET"
" address=%Q, attribute=%i, precision=%i, type=%i,"
" decimal=%lf, bias=%lf, description=%Q, value=%Q, unit=%Q "
"WHERE driver_name=%Q AND group_name=%Q AND name=%Q",
tag->address, tag->attribute, tag->precision, tag->type,
tag->decimal, tag->bias, tag->description, "", tag->unit,
driver_name, group_name, tag->name);
return rv;
}
+8 -4
View File
@@ -156,7 +156,8 @@ driver_1 = {
"decimal": 0.0,
"bias": 1.0,
"address": "1!400001",
"description": ""
"description": "",
"unit": ""
},
{
"type": 3,
@@ -166,7 +167,8 @@ driver_1 = {
"decimal": 0.0,
"bias": 1.0,
"address": "1!400002",
"description": ""
"description": "",
"unit": ""
}
],
},
@@ -204,7 +206,8 @@ driver_2 = {
"decimal": 0.0,
"bias": 1.0,
"address": "1!400001",
"description": ""
"description": "",
"unit": ""
},
{
"type": 3,
@@ -214,7 +217,8 @@ driver_2 = {
"decimal": 0.0,
"bias": 1.0,
"address": "1!400002",
"description": ""
"description": "",
"unit": ""
}
],
}
+43
View File
@@ -14,6 +14,8 @@ hold_int16_bit = [{"name": "hold_int16_type", "address": "1!400001",
"attribute": NEU_TAG_ATTRIBUTE_RW, "type": NEU_TYPE_BIT}]
hold_int16_description = [{"name": "hold_int16_description", "address": "1!400001",
"attribute": NEU_TAG_ATTRIBUTE_RW, "type": NEU_TYPE_INT16, "description": "description info"}]
hold_int16_unit = [{"name": "hold_int16_unit", "address": "1!400001",
"attribute": NEU_TAG_ATTRIBUTE_RW, "type": NEU_TYPE_INT16, "unit": "unit_info"}]
hold_int16_decimal = [{"name": "hold_int16_decimal", "address": "1!400001",
"attribute": NEU_TAG_ATTRIBUTE_RW, "type": NEU_TYPE_INT16, "decimal": 0.1}]
hold_int16_bias = [{"name": "hold_int16_bias", "address": "1!400001",
@@ -1013,3 +1015,44 @@ class TestTag:
old_name="some_tag", new_name="new_tag")
assert 404 == response.status_code
assert NEU_ERR_NODE_NOT_EXIST == response.json()['error']
@description(given="a node and group", when="add a tag with unit", then="add success")
def test_add_tag_with_unit(self):
response = api.add_tags(node="modbus-tcp", group="group1", tags=hold_int16_unit)
assert 200 == response.status_code
assert NEU_ERR_SUCCESS == response.json()['error']
response = api.get_tags(node="modbus-tcp", group="group1")
assert 200 == response.status_code
assert "hold_int16_unit" == response.json()["tags"][0]["name"]
assert "1!400001" == response.json()["tags"][0]["address"]
assert NEU_TAG_ATTRIBUTE_RW == response.json()["tags"][0]["attribute"]
assert NEU_TYPE_INT16 == response.json()["tags"][0]["type"]
assert "unit_info" == response.json()["tags"][0]["unit"]
response = api.del_tags(node="modbus-tcp", group="group1", tags=["hold_int16_unit"])
assert 200 == response.status_code
assert NEU_ERR_SUCCESS == response.json()['error']
@description(given="a node and group", when="add a tag and update with unit", then="update success")
def test_update_tag_with_unit(self):
api.add_tags_check(node="modbus-tcp", group="group1", tags=hold_int16)
tag = {
**hold_int16[0],
"unit": "unit_info",
}
try:
response = api.update_tags(node="modbus-tcp", group="group1", tags=[tag])
assert 200 == response.status_code
assert NEU_ERR_SUCCESS == response.json()['error']
response = api.get_tags(node="modbus-tcp", group="group1")
assert 200 == response.status_code
assert tag["name"] == response.json()["tags"][0]["name"]
assert tag["address"] == response.json()["tags"][0]["address"]
assert tag["attribute"] == response.json()["tags"][0]["attribute"]
assert tag["type"] == response.json()["tags"][0]["type"]
assert tag["unit"] == response.json()["tags"][0]["unit"]
finally:
api.del_tags(node="modbus-tcp", group="group1", tags=[tag["name"]])