Heex provides a Monitor class that will be instantiated in your implementations to monitor the dataflow of your edge system. The Monitor class is a generic class that can be used to monitor several types of dataflows like boolean, string, float, integers, geographic, etc. Do you happen to have a use case that is not covered by our ready-to-use classes ? Don’t worry, just contact us at contact@heex.io and we will work with you to provide a custom class.

Monitor Build

To integrate monitors and recorders in your project you have to build with Heex libraries. See HeexSDK integration for details.

Monitor main APIs

Monitor(id, serverIp, serverPort)
  • Id : Monitor implementation ID, that can be retrieved on the Heex Cloud
  • serverIp : IP address to contact Heex Kernel
  • serverPort : Port to contact Heex Kernel
awaitReady() : To wait until the monitor is ready to receive data. Please ensure this function returns True before continuing. getMonitorSignals(triggerId="", signalName="") : Returns all the MonitoringSignal your monitor is monitoring. triggerId and signalName can be left empty or filled if you want to filter specific signals. setConditionState(state, signalName, timestamp="") : Set the state of given monitoring signal condition. This allows to trigger the condition state of any monitoring condition of a signal. NOTE: currently we only support this method for CUSTOM signals. updateValue(inputValue) : To update the in-memory value of your signal, and communicate with the Heex Kernel when the conditions set on the Heex Cloud are met. updateValue(inputValue, timestamp="") : Call updateValue with the timestamp in the form of a string. updateValueBySignalName(inputValue, timestamp="", signalName="") : Call updateValue but only for the signal with the specified name. Timestamp can be set to "" if you want us to set the timestamp at local time. These APIs are template functions, so you can use them with any type of dataflow, in particular:
  • bool : boolean dataflow
  • int, uint, short, long : integer dataflow
  • float, double : float dataflow
  • string, char* : string dataflow
  • HeexGps : geographic dataflow (see below)

HeexGps structure

/// @brief Structure to get GPS informations.
///
/// @param lat The latitude coordinate
/// @param lon The longitude coordinate
struct HeexGps
{
  double lat{0.0}; ///< The latitude coordinate
  double lon{0.0}; ///< The longitude coordinate

  HeexGps() = default;
  HeexGps(const double& latIn, const double& lonIn) : lat{latIn}, lon{lonIn} {};
  HeexGps(const HeexGps& other)            = default;
  HeexGps& operator=(const HeexGps& other) = default;
  HeexGps& operator=(HeexGps&& other)      = default;

  bool operator==(const HeexGps& other) const { return lat == other.lat && lon == other.lon; }
  bool operator!=(const HeexGps& other) const { return !(*this == other); }
};

MonitoringSignal structure

/// @brief Structure to hold a monitoring signal
///
/// @param id The ID of the signal.
/// @param name The name of the signal. For ROS topics, the format is '/topicName>subtopic1>subtopic...'. eg: '/imu>angular_velocity>x'
/// @param unit The unit of the signal. enum value (eg: 1 -> METER_PER_SECOND, 2 -> METER, 3 -> KILOMETER, etc.)
/// @param rosTopicType The ROS topic type of the signal. Only used for ROS topics, eg 'sensor_msgs/msg/NavSatFix'
/// @param datasourceId The ID of the datasource this signal is associated to.
/// @param datasourceName The name of the datasource this signal is associated to.
/// @param signalType The type of the signal. enum value (eg: 1 -> INTEGER, 2 -> NUMBER, 7 -> STRING, 6 -> BOOLEAN...)
/// @param signalOperator The operator of the signal. enum value (eg: 1 -> IN, 2 -> OUT, 10 -> LESS_THAN, etc.)
/// @param valueType The type of the  monitored value. (eg: "double", "string", "bool", "array", "zone"...)
/// @param value The stringified triggering value. (eg: "1.23", "true", "['a', 'b', 'c']", "zone1", "zone2"...)
struct MonitoringSignal
{
  std::string id{};   ///< The ID of the signal.
  std::string name{}; ///< The name of the signal. For ROS topics, the format is '/topicName>subtopic1>subtopic...'. eg: '/imu>angular_velocity>x'
  int unit{static_cast<int>(apiinterface::Unit::UNIT_UNSPECIFIED)};           ///< The unit of the signal. enum value (eg: 1 -> METER_PER_SECOND, 2 -> METER, 3 -> KILOMETER, etc.)
  std::string rosTopicType{};                                                 ///< The ROS topic type of the signal. Only used for ROS topics, eg 'sensor_msgs/msg/NavSatFix'
  std::string datasourceId{};                                                 ///< The ID of the datasource this signal is associated to.
  std::string datasourceName{};                                               ///< The name of the datasource this signal is associated to.
  int signalType{static_cast<int>(apiinterface::SignalType::ST_UNSPECIFIED)}; ///< The type of the signal enum value (eg: 1 -> INTEGER, 2 -> NUMBER, 7 -> STRING, 6 -> BOOLEAN...)
  int signalOperator{static_cast<int>(apiinterface::Operator::OP_UNSPECIFIED)}; ///< The operator of the signal enum value (eg: 1 -> IN, 2 -> OUT, 10 -> LESS_THAN, etc.)
  std::string valueType{};                                                      ///< The type of the  monitored value. (eg: "double", "string", "bool", "array", "zone"...)
  std::string value{}; ///< The stringified triggering value. (eg: "1.23", "true", "['a', 'b', 'c']", "some text", <zone>...)

  // Copy assignment operator
  MonitoringSignal& operator=(const MonitoringSignal& other) = default;

  bool operator==(const MonitoringSignal& other) const
  {
    return (
        id == other.id && name == other.name && unit == other.unit && rosTopicType == other.rosTopicType && datasourceId == other.datasourceId &&
        datasourceName == other.datasourceName && signalType == other.signalType && signalOperator == other.signalOperator && valueType == other.valueType && value == other.value);
  }

  /// @brief Convert the unit to a stringified enum value for human readability (ie: 0 -> UNIT_UNSPECIFIED, 1 -> METER_PER_SECOND, etc.)
  /// @return the stringified enum value
  std::string unitToString() const
  {
    auto u = static_cast<apiinterface::Unit>(unit);
    return apiinterface::Unit_Name(u);
  }

  /// @brief Convert the signal type to a stringified enum value for human readability (ie: 0 -> ST_UNSPECIFIED, 1 -> INTEGER, etc.)
  /// @return the stringified enum value
  std::string signalTypeToString() const
  {
    auto t = static_cast<apiinterface::SignalType>(signalType);
    return apiinterface::SignalType_Name(t);
  }

  /// @brief Convert the signal operator to a stringified enum value for human readability (ie: 0 -> OP_UNSPECIFIED, 1 -> IN, 2 -> OUT, etc.)
  /// @return the stringified enum value
  std::string signalOperatorToString() const
  {
    auto o = static_cast<apiinterface::Operator>(signalOperator);
    return apiinterface::Operator_Name(o);
  }
};

Monitor implementation

Let’s write a small example. The Monitor can monitor a speed dataflow in a range.
You have to include Monitor.hThen, instantiation is done calling the constructor:
Monitor myMonitor("m-1a7453c0-ef64-4290-a9c3-5019e8bb43fa", "127.0.0.1", 4242);
if (myMonitor.awaitReady() == false) // awaits the connection with the kernel.
{
  return EXIT_FAILURE;
}
Using the awaitReady() allows to wait until your monitor establishes a connection with the Heex Kernel. The monitor will detect events based on the values that are sent to it, so you should call updateValue() method with the value of your signal. It could be at regular time intervals or when the signal changes. This is highly dependant to your edge system. To do that, use the following code:
my_monitor.updateValue(speed);
🎉 CONGRATULATIONS! This is it!
You don’t need to care about the bounds set in the Heex Cloud when specifying the trigger. All the checking will occur behind the scene and the Heex Agent will take care of detecting when matching conditions are met to trigger events.
ℹ️ Info: timestamp It is recommended to call UpdateValue method, giving as second argument the exact timestamp of your signal value formatted in ISO 8601-1:2019. Otherwise the current system time is applied by default to your signal value.
For more information go to Timestamp Formatting page.

Monitor Samples

You can check the samples here.