Обработчики на платформе RIC

Платформа позволяет осуществлять контроль текущих значений параметров объекта, которые регистрируются его датчиками. Все данные, полученные от устройства, сохраняются на платформе и в любой момент доступны для последующего анализа. Однако зачастую при анализе данных появляется необходимость в дополнительных расчетах на базе полученных значений. Или же наоборот, могут быть случаи, когда получены данные с избыточной или некорректной информацией. В подобных ситуациях необходима дополнительная фильтрация.
Для этого в архитектуре платформы существует отдельный слой - обработчики, которые позволяют обрабатывать входной пакет данных с целью его коррекции или дополнения. Данные могут быть обработаны таким образом, чтобы можно было, например, рассчитывать расстояние, пройденное транспортным средством, оперируя количеством оборотов колеса и длиной его окружности; осуществлять перевод величины одной единицы измерения в другую; фильтровать пакеты данных, отбрасывая избыточную информацию и оставляя наиболее существенную, и многое другое. Подобные действия можно реализовать в обработчике и затем запустить его. Для создания обработчика необходимо написать исходный код на языке программирования JavaScript версии ES6. Таким образом, вы сами реализуете алгоритм, с помощью которого можно учитывать все аспекты обработки данных для ваших пакетов.

Здравствуйте! В обработчике пытаюсь сделать логику, что бы парсить входящее сообщение. А именно хочу сжать передаваемый пакет на сервер, такт как часто некоторые параметры бывыют равны нулю или повторяются. А далее в обработчике вернуть в “нормальный” вид.
Типа:
раньше строка была:
“0#0#0#0#0#0#0#0#0#0#0#14#ea60#3e8#ea60#64#ea60#0#94#0#0#0#0#0#1e#0#0#0#0#1#2#0#0#0#2#0#0#0#1#f#0#1#0#0#3#0#818#0#1429#0#216.06#”

в сжатом варианте "|11#14#ea60#3e8#ea60#64#ea60##94#|5#1e#|4#1#2#|3#2#|3#1#f##1#|2@3##818##1429#@216.06@
"
Пытался сделать в обработчике отдельную функцию, но выдает ошибку:
“TypeError: Cannot read property ‘toString’ of undefined”

Пока не получилось победить…
Подскажите, что не так, пожалуйста

Добрый день. А код самого обработчика можете приложить? Ну или в чат личный скинуть. Скорей всего какое то значение string undefined или null.

// пример прихода и рабора данных
// #region test text
// St#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#20#60000#1000#60000#100#60000#0#147#0#0#0#0#0#30#0#0#0#0#1#2#0#0#0#2#0#0#59#2#23#0#2#0#0#125.00#100#0.13#041140#55.7259#49.1507#0#125.8##SMARTGEN

//Kovali_azimut_20#
//0@0@0@0@0@0@0@0@0@0@0@0@0@0@0@0@0@20@60000@1000@60000@100@60000@0@148@
//0@0@0@0@0@30@0@0@0@0@1@2@0@0@0@2@0@0@59@2@23@0@2@0@0@
//#43@1000@41c@0@1429@#
//50.00@9@0.13#
//F@55.623221@49.156243@F@F
//#SMARTGEN

//Kovali_azimut_20#0@0@0@0@0@0@0@0@0@0@0@0@0@0@0@0@0@20@60000@1000@60000@100@60000@0@148@0@0@0@0@0@30@0@0@0@0@1@2@0@0@0@2@0@0@59@2@23@0@2@0@0@#43@1000@41c@0@1429@#50.00@9@0.14#F@55.623221@49.156243@F@F#SMARTGEN
//TypeError: Register_array is not a function
//TypeError: Cannot read property ‘fill’ of undefined
//ReferenceError: NONE is not defined
//Kovali_azimut_20#213@0@0@214@0@214@499@0@0@0@0@0@0@0@0@0@0@42@3145@0@96@75@277@0@135@0@0@0@0@0@30@0@0@0@0@1@2@0@0@0@2@0@0@42@52@6@0@156@0@204@#40@0@800@2004@1402@#65.53@41@94@0.13#F@55.623221@49.156243@F@F#SMARTGEN

//#endregion
function Split_string(mes, del, add_del){
var arr = mes.split(del);
var _string = “”;
for (let i = 0; i < arr.length; i++) {
if (arr[i].includes(add_del)){
var cell = arr[i].split(add_del);
if (cell[0] === ‘’) {cell[0] = ‘0’}
for (let c = 0; c < Number(cell[1]); c++){
_string = _string + cell[0] + ‘#’;
}
}
else if (arr[i] === ‘’){
_string = _string + ‘0’ + ‘#’;
}
else {
_string = _string + arr[i] + ‘#’;
}
}
return _string;
}

// переменные сос зачениями coils регистров c
// #region coil smartgen
// data[0]
const _Common_Alarm = 0b0000000000000000;//1
const _Common_Warning_Alarm = 0b0000000000000001;//2
const _Common_Shutdown_Alarm = 0b0000000000000010;//3
const _Remote_Mode = 0b0000000000000100;//4
const _Remote_Lock = 0b0000000000001000;//5
const null1 = 0b0000000000010000;//6
const _Gen_with_Load = 0b0000000000100000;//7
const _Mains_with_Load = 0b0000000001000000;//8
const _Emergency_Stop = 0b0000000010000000;//9
const _Overspeed_Alarm_Shutdown = 0b0000000100000000;//10
const _Underspeed_Alarm_Shutdown = 0b0000001000000000;//11
const _Speed_Signal_Loss_Shutdown = 0b0000010000000000;//12
const _Overfrequency_Shutdown = 0b0000100000000000;//13
const _Underfrequency_Shutdown = 0b0001000000000000;//14
const _Overvoltage_Shutdown = 0b0010000000000000;//15
const _Undervoltage_Shutdow = 0b0100000000000000;//16

// data[1]
const _Gen_Overcurrent_Shutdown = 0b0000000000000001;//17
const _Crank_Failure = 0b0000000000000010;//18
const _High_Temperature_Shutdown = 0b0000000000000100;//19
const _Low_Oil_Pressure_Shutdown = 0b0000000000001000;//20
const _Frequency_Loss_Alarm = 0b0000000000010000;//21
const _Input_Port_Shutdown_Alarm = 0b0000000000100000;//22
const _Low_Fuel_Level_Shutdown_Alarm = 0b0000000001000000;//23
const _Low_Coolant_Level_Shutdown_Alarm = 0b0000000010000000;//24
const _High_Water_Temperature_Warn_Alarm = 0b0000000100000000;//25
const _Low_Oil_Pressure_Warn_Alarm = 0b0000001000000000;//26
const _Gen_Overcurrent_Warn_Alarm = 0b0000010000000000;//27
const _Stop_Failure_Warn = 0b0000100000000000;//28
const _Low_Oil_Level_Warn = 0b0001000000000000;//29
const _Charge_Failure_Warn = 0b0010000000000000;//30
const _Battery_Low_Warn_Alarm = 0b0100000000000000;//31
const _Battery_Volt_High_Warn_Alarm = 0b1000000000000000;//32

// data[2]
const _Input_Port_Warn_Alarm = 0b1000000000000001;//33
const _Speed_Signal_Loss_Warn = 0b0000000000000010;//34
const _Low_Coolant_Level_Warn = 0b0000000000000100;//35
const _Temp_Sensor_Open_Warn = 0b0000000000001000;//36
const _Oil_Pressure_Sensor_Open_Warn = 0b0000000000010000;//37
const _Maintenance_Due_Warn = 0b0000000000100000;//38
const _Charger_Fails_to_Charge_Warn = 0b0000000001000000;//39
const _Over_Power_Warn = 0b0000000010000000;//40
const _Test_Mode = 0b0000000100000000;//41
const _Auto_Mode = 0b0000001000000000;//42
const _Manual_Mode = 0b0000010000000000;//43
const _Stop_Mode = 0b0000100000000000;//44
const _Temp_Sensor_Open_Shutdown = 0b0001000000000000;//45
const _Oil_Pressure_Sensor_Open_Shutdown = 0b0010000000000000;//46
const _Maintenance_Due_Shutdown_Alarm = 0b0100000000000000;//47
const _Over_Power_Shutdown_Alarm = 0b1000000000000000;//48

// data[3]

const _Emergency_Stop_Input = 0b1000000000000001;//49
const _Aux_Input_1 = 0b0000000000000010;//50
const _Aux_Input_2 = 0b0000000000000100;//51
const _Aux_Input_3 = 0b0000000000001000;//52
const _Aux_Input_4 = 0b0000000000010000;//53
const _Aux_Input_5 = 0b0000000000100000;//54
const _Gen_Switch_Failure_Warn = 0b0000000001000000;//55
const _Mains_Switch_Failure_Warn = 0b0000000010000000;//56
const _Start_Relay_Output = 0b0000000100000000;//57
const _Fuel_Relay_Output = 0b0000001000000000;//58
const _Aux_Output_1 = 0b0000010000000000;//59
const _Aux_Output_2 = 0b0000100000000000;//60
const _Aux_Output_3 = 0b0001000000000000;//61
const _Aux_Output_4 = 0b0010000000000000;//62
const _null2 = 0b0100000000000000;//63
const _null3 = 0b1000000000000000;//64

// data[4]
const _Mains_Fault = 0b1000000000000001;//65
const _Mains_Normal = 0b0000000000000010;//66
const _Mains_Overvoltage = 0b0000000000000100;//67
const _Mains_Undervoltage = 0b0000000000001000;//68
const _Mains_Loss_of_Phase = 0b0000000000010000;//69
const _Mains_Blackout = 0b0000000000100000;//70
const _null4 = 0b0000000001000000;//71
const _null5 = 0b0000000010000000;//72
const _Gen_Normal = 0b0000000100000000;//73
const _Gen_Overvoltage = 0b0000001000000000;//74
const _Gen_Undervoltage = 0b0000010000000000;//75
const _Gen_Overfrequency = 0b0000100000000000;//76
const _Gen_Underfrequency = 0b0001000000000000;//77
const _Gen_Overcurrent_Warn = 0b0010000000000000;//78
const _In_Scheduled_Not_Run = 0b0100000000000000;//79
const _ECU_Warn = 0b1000000000000000;//80
// #endregion

function process(in_message) {

// var array = in_message.split(‘#’);
var array = in_message.split(‘@’);
// var Register_array = array[0].split(‘@’);

// var registers = array[0].split(‘#’);
// var _string = “”;
// for (let i = 0; i < registers.length; i++) {
// if (registers[i].includes(‘|’)){
// var cell = registers[i].split(‘|’);
// if (cell[0] === ‘’) {cell[0] = ‘0’}
// for (let c = 0; c < Number(cell[1]); c++){
// _string = _string + cell[0] + ‘#’;
// }
// }
// else if (registers[i] === ‘’){
// _string = _string + ‘0’ + ‘#’;
// }
// else {
// _string = _string + registers[i] + ‘#’;
// }
// }

var Register_array = Split_string(array[0], ‘#’, ‘|’).split(‘#’);
var Coils_array = array[1].split(‘@’);
// var Coils_array = Split_string(array[1].split(‘#’));
var System_array = array[2].split(‘@’);
// var System_array = Split_string(array[2].split(‘#’));
var GPS_array = array[1].split(‘@’);
// var GPS_array = Split_string(array[3].split(‘#’));
const Controller = array[1];

// if (Register_array.length < 2){ Register_array = Array(50).fill(“NONE”)}
// if (Coils_array.length < 2){ Coils_array = Array(5).fill(“NONE”)}

    // сеть
    const MV_L1       =         Register_array[0];         // напряжение 1 фазы
    const MV_L2       =         Register_array[1];         // напряжение 2 фазы
    const MV_L3       =         Register_array[2];         // напряжение 3 фазы
    const MV_L1_L2    =         Register_array[3];         // напряжение межазное
    const MV_L2_L3    =         Register_array[4];         // напряжение межазное
    const MV_L3_L1    =         Register_array[5];         // напряжение межазное
    const MF          =         Register_array[6];         // частота
    // генератор
    const GV_L1       =         Register_array[7];         // напряжение 1 фазы
    const GV_L2       =         Register_array[8];         // напряжение 2 фазы
    const GV_L3       =         Register_array[9];        // напряжение 3 фазы
    const GV_L1_L2    =         Register_array[10];        // напряжение межазное
    const GV_L2_L3    =         Register_array[11];        // напряжение межазное
    const GV_L3_L1    =         Register_array[12];        // напряжение межазное
    const GF          =         Register_array[13];        // частота

    const CUR_L1      =         Register_array[14];        // ток 1 фазы
    const CUR_L2      =         Register_array[15];        // ток 2 фазы
    const CUR_L3      =         Register_array[16];        // ток 3 фазы

    const Temp_eng    =         Register_array[17];        // температура двигателя
    //const GC_L2       =         array[19];        // ток 2 фазы
    const Oil_pres    =         Register_array[19];        // давление масла
    ///const GC_L1       =         array[21];        // ток 1 фазы
    const Fuel_level  =         Register_array[21];        // уровень топлива
    //const GC_L3       =         array[23];        // ток 3 фазы
    const Speed_rpm   =         Register_array[23];        // обороты двигателя
    const V_bat_gen   =         Register_array[24]/10;     // напряжение АКБ
    const V_ch_gen    =         Register_array[25]/10;     // напряжение заряда АКБ

    /*
    const GC_L1       =         array[28];        // ток 1 фазы
    const GC_L2       =         array[29];        // ток 2 фазы
    const GC_L3       =         array[30];        // ток 3 фазы
    */
    
    const Last_time   =         Register_array[30];        // время сервиса
    

    /*
    const GC_L2       =         array[32]; // ток 2 фазы
    const GC_L3       =         array[33]; // ток 3 фазы
    const GC_L2       =         array[34]; // ток 2 фазы
    const GC_L3       =         array[35]; // ток 3 фазы
    const GC_L2       =         array[36]; // ток 2 фазы
    const GC_L3       =         array[37]; // ток 3 фазы
    const GC_L2       =         array[38]; // ток 2 фазы
    const GC_L3       =         array[39]; // ток 3 фазы
    const GC_L2       =         array[40]; // ток 2 фазы
    const GC_L3       =         array[41]; // ток 3 фазы
    const GC_L2       =         array[42]; // ток 2 фазы
    const GC_L3       =         array[43]; // ток 3 фазы
    */

    const Time_houre  =         Register_array[43]; // Моточасы часы
    const Time_Min    =         Register_array[44]; // Моточасы минуты
    const Time_Sec    =         Register_array[45]; // Моточасы секунды
    
    const Time        =         Time_houre.toString() + ':' + Time_Min.toString() + ':' + Time_Sec.toString();

    
    // const GC_L3       =         array[47]; // ток 3 фазы
    
    const Runs        =         Register_array[47]; // Количество запусков
    
    /*
    const GC_L3       =         array[49]; // ток 3 фазы
    const GC_L2       =         array[50]; // ток 2 фазы
    */
    //parseInt(num, baseFrom).toString(baseTo);
    //const all_coils   =         array[51];            // значение всех коилс массивом разделителем "@" в HEX
    //var array_coils   =         all_coils.split("@");
    
    const coils_0     =         parseInt(Coils_array[0], 16);
    const coils_1     =         parseInt(Coils_array[1], 16);
    const coils_2     =         parseInt(Coils_array[2], 16);
    const coils_3     =         parseInt(Coils_array[3], 16);
    const coils_4     =         parseInt(Coils_array[4], 16);

    const coils_2_str =         coils_2.toString(2);

    var mode;
    if (_Stop_Mode == (_Stop_Mode & coils_2)) {
       mode = "STOP";
    }
    if (_Manual_Mode == (_Manual_Mode & coils_2)) {
       mode = "MAN";
    }
    if (_Auto_Mode == (_Auto_Mode & coils_2)) {
       mode = "AUTO";
    }
    if (_Test_Mode == (_Test_Mode & coils_2)) {
       mode = "TEST";
    }
    
    var alarm = "";
    if (_Emergency_Stop_Input  == (_Emergency_Stop_Input  & coils_3)) {
       alarm += " Em Stop";
    }
    

    var gen_act;
      if (_Gen_with_Load == (_Gen_with_Load & coils_0)) {
        gen_act = "Closed";
      }
      else{
        gen_act = "Open"
      }
    var mains_act;
      if (_Mains_with_Load == (_Mains_with_Load & coils_0)) {
        mains_act = "Closed";
      }
      else{
        mains_act = "Open"
      }


    const ballans     =         System_array[0];
    const CSQ         =         System_array[1];
    const V_bat_sim   =         System_array[2];
    const V_bat_adc   =         System_array[3];

    
    const Time_GPS    =         GPS_array[0];
    const lat_GPS     =         Number(GPS_array[1]);
    const lon_GPS     =         Number(GPS_array[2]);
    const Sat_GPS     =         Number(GPS_array[3]);
    const Alt_GPS     =         Number(GPS_array[4]);

    //const num_GPS = array[25];
    //const alt_GPS = array[26];

    // St#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#20#60000#1000#60000#100#60000#0#147#0#0#0#0#0#30#0#0#0#0#1#2#0#0#0#2#0#0#59#2#23#0#2#0#0#0.00#100##090555#55.7188#49.1400#0#149.4##SMARTGEN

    return {  Controller,
              MV_L1,        MV_L2,        MV_L3,
              //MV_L1_L2,     MV_L2_L3,     MV_L3_L1,
              MF,
              GV_L1,        GV_L2,        GV_L3,
              //GV_L1_L2,     GV_L2_L3,     GV_L3_L1,
              GF,
              CUR_L1,       CUR_L2,       CUR_L3,

              Temp_eng,     Oil_pres,     Fuel_level,     Speed_rpm,
              V_bat_gen,    V_ch_gen,
              Last_time,
              Time,
              Runs,

              ballans,      CSQ,          V_bat_sim,    V_bat_adc,

              Time_GPS,     lat_GPS,      lon_GPS,      Sat_GPS,      Alt_GPS,

              mode, alarm,
              gen_act, mains_act

    }

}

Обычно можно нажать на плашку с ошибкой на странице состояния, для того чтобы перейти в редактор кода обработчиков в то место, где произошла ошибка.
Курсор будет указазывать на нужную строку и столбец

Screenshot from 2023-11-29 11-38-56

К сожалению из-за бага в данный момент сбилась нумерация строк, и курсор будет указывать немного не туда.
Баг в ближайшем релизе постараемся исправить.

В данный момент ошибка возникает у вас на 243 строке обработчика

          const Time        =         Time_houre.toString() + ':' + Time_Min.toString() + ':' + Time_Sec.toString();
                                                                                                         ^

TypeError: Cannot read properties of undefined (reading 'toString')

Так же у вас обработчик имеет довольно внушительный размер, работать с таким в небольшом окне редактора скорее всего неудобно.

Я предложил бы установить себе какой-нибудь JavaScript рантайм:

Сохранить обработчик в файл test.js (например)
И попробовать позапускать его локально.

> node ./test.js
# или
> deno run ./test.js

Передать в обработчик тестовые данные и вывести результат можно дописав эти строки в конце файла с обработчиком:

const result = process("|11#14#ea60#3e8#ea60#64#ea60##94#|5#1e#|4#1#2#|3#2#|3#1#f##1#|2@3##818##1429#@216.06@");
console.log(result);

Если после этого установить себе ещё VS Code:

То получим полноценный инструмент для отладки

Для вашей изначальной задачи удобно использовать метод Array.flatMap()
Он позволяет пройтись по элементам массива с помощью функции, которая помимо обычных результирующих значений - может возвращать ещё массивы таких значений.

/**
 * @param {string} str
 * @returns {string[]}
 */
function decompress(str) {
  return str.split("#").flatMap((it) => {
    // если элемент начинается с `|`  
    if (it.startsWith("|")) {
      // пробуем достать из него кол-во нулей
      const zeros = Number(it.replace("|", ""));
      if (isFinite(zeros)) {
        // возвращаем массив заполненный нулями
        return Array(zeros).fill("0");
      }
    }
    // иначе просто берём текущий элемент
    return it;
  });
}

В результате получится один плоский массив.

1 лайк