Skip to content

Commit

Permalink
Add MQTT back #20
Browse files Browse the repository at this point in the history
  • Loading branch information
Lecrapouille committed Jun 30, 2024
1 parent 2244692 commit 6578376
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 14 deletions.
61 changes: 49 additions & 12 deletions doc/mqtt.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
# Controlling the editor through MQTT commands

When opening a petri json file (i.e. `foobar.json`). The editor will listening
the MQTT topic `"pneditor/foobar"` on localhost with port 1883 for MQTT
commands such as `"T0"` for triggering the transition T0 or `"P0"` for incrementing
of one the number of tokens in the place P0. Dummy file have their topic named
`"editor/petri.json"`.
The editor starts a MQTT client, with by default localhost with port 1883 (you can change
them from the Makefile. Search for `MQTT_BROKER_ADDR` and `MQTT_BROKER_PORT`).

TODO: implement commands such as `"T0;T1;T2"` or `"P4+2"` or `"P4-1"` or `"P4=2"`.
TBD: topics such as `"pneditor/foobar/T0"` with value `true/false` or
`"pneditor/foobar/P0"` with values such as `1`?
For more information concerning MQTT, read this
[document](https://www.howtoforge.com/how-to-install-mosquitto-mqtt-message-broker-on-debian-11/).

## Load a new Petri net

For example, you can type on your console:
Note: if you want to control the net through MQTT commands, better to avoid creating "timed" net
(timed event graph and timed Petri net), create instead Petri net or GRAFCET.

The message content is the same JSON format than the one used for saving/loading files. See [here](save.md)
for more information.

Example:
```
sudo mosquitto_pub -h localhost -t "pneditor/foobar" -m "T0"
mosquitto_pub -h localhost -t "tpne/load" -m '{ "revision": 3, "type":
"Petri net", "nets": [ { "name": "Petri net",
"places": [ { "id": 0, "caption": "P0", "tokens": 1, "x": 244, "y": 153 },
{ "id": 1, "caption": "P1", "tokens": 0, "x": 356, "y": 260 } ],
"transitions": [ { "id": 0, "caption": "T0", "x": 298, "y": 207, "angle": 0 } ],
"arcs": [ { "from": "P0", "to": "T0" }, { "from": "T0", "to": "P1", "duration": 3 }
] } ] }'
```

For more information concerning MQTT, read this
[document](https://www.howtoforge.com/how-to-install-mosquitto-mqtt-message-broker-on-debian-11/).
Constrain: the simulation shall not running when loading the net.

## Start/Stop simulation

Before firing transitions, you have to start the simulation.

```
mosquitto_pub -h localhost -t "tpne/start" -m ''
```

For stopping:
```
mosquitto_pub -h localhost -t "tpne/stop" -m ''
```

## Firing transitions

The message to send is a list of '1' or '0' characters (string). One character by transitions.

Let suppose, you have 2 transitions in your net. The message length shall be 2. Let suppose you want
to fire transition 1 but not the second. The message will be "10".

```
mosquitto_pub -h localhost -t "tpne/fire" -m '10'
```

Constrain:
- The simulation shall running.
- The message length shall match the number of transitions.
14 changes: 14 additions & 0 deletions src/Editor/DearImGui/Backends/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
###################################################
# Set MQTT Library.
#
ifneq ($(OS),Emscripten)
INCLUDES += $(THIRDPART_DIR)/MQTT/include
DEFINES += -DMQTT_BROKER_ADDR=\"localhost\"
DEFINES += -DMQTT_BROKER_PORT=1883
DEFINES += -DWITH_MQTT
PKG_LIBS += libmosquitto
GUI_FILES += $(THIRDPART_DIR)/MQTT/src/MQTT.cpp
else
DEFINES += -UWITH_MQTT
endif

###################################################
# If compiling for HTML5 (Emscripten) then force
# using Raylib backend since GLFW3 is not compilable.
Expand Down
99 changes: 99 additions & 0 deletions src/Editor/DearImGui/Editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@
#include "Editor/DearImGui/KeyBindings.hpp"
#include "Utils/Utils.hpp"

#ifdef WITH_MQTT
# ifndef MQTT_BROKER_ADDR
# error "MQTT_BROKER_ADDR shall be defined"
# endif
# ifndef MQTT_BROKER_PORT
# error "MQTT_BROKER_PORT shall be defined"
# endif
#endif

namespace tpne {

//! \brief path of the file storing dear imgui widgets. Cannot be placed
Expand All @@ -37,6 +46,9 @@ static std::string g_ini_filename = "imgui.ini";
Editor::Editor(size_t const width, size_t const height,
std::string const& title)
: Application(width, height, title),
#ifdef WITH_MQTT
MQTT(MQTT_BROKER_ADDR, MQTT_BROKER_PORT),
#endif
m_path(GET_DATA_PATH),
m_simulation(m_net, m_messages),
m_view(*this)
Expand Down Expand Up @@ -65,6 +77,93 @@ Editor::Editor(size_t const width, size_t const height,
ImGui::StyleColorsDark();
}

#ifdef WITH_MQTT
//------------------------------------------------------------------------------
void Editor::onConnected(int /*rc*/)
{
std::cout << "Connected to MQTT broker" << std::endl;

// Load a Petri net using the formalism used for TPNE json files. For example
// mosquitto_pub -h localhost -t "tpne/load" -m '{ "revision": 3, "type":
// "Petri net", "nets": [ { "name": "hello world",
// "places": [ { "id": 0, "caption": "P0", "tokens": 1, "x": 244, "y": 153 },
// { "id": 1, "caption": "P1", "tokens": 0, "x": 356, "y": 260 } ],
// "transitions": [ { "id": 0, "caption": "T0", "x": 298, "y": 207, "angle": 0 } ],
// "arcs": [ { "from": "P0", "to": "T0" }, { "from": "T0", "to": "P1", "duration": 3 }
// ] } ] }'
subscribe("tpne/load", [&](MQTT::Message const& msg){
std::cout << "load\n";
if (m_simulation.running)
{
m_messages.setError("MQTT: cannot load new Petri net while the simulation is still in progress");
return ;
}
const char* message = static_cast<const char*>(msg.payload);

// To temporary file
std::string path("/tmp/petri.json");
std::ofstream file(path);
file << message;
file.close();

// Import the file
bool shall_springify;
std::string error = loadFromFile(m_net, path, shall_springify);
if (error.empty())
{
m_messages.setInfo("Loaded with success " + path);
}
else
{
m_messages.setError(error);
}
}, MQTT::QoS::QoS0);

// Start the simulation for Petri net and GRAFCET.
// mosquitto_pub -h localhost -t "tpne/start" -m ''
subscribe("tpne/start", [&](MQTT::Message const& /*msg*/){
if ((m_net.type() == TypeOfNet::TimedEventGraph) || (m_net.type() == TypeOfNet::TimedPetriNet))
{
m_messages.setError("MQTT: Please convert first to non timed net before starting simulation");
return ;
}
m_simulation.running = true;
framerate(30);
}, MQTT::QoS::QoS0);

// Stop the simulation.
// mosquitto_pub -h localhost -t "tpne/stop" -m ''
subscribe("tpne/stop", [&](MQTT::Message const& /*msg*/){
m_simulation.running = false;
framerate(60);
}, MQTT::QoS::QoS0);

// Fire transitions.
// mosquitto_pub -h localhost -t "tpne/fire" -m '10100'
subscribe("tpne/fire", [&](MQTT::Message const& msg){
if (!m_simulation.running)
{
m_messages.setError("MQTT: The simulation is not running");
return ;
}
const char* message = static_cast<const char*>(msg.payload);
Net::Transitions& transitions = m_net.transitions();
size_t i = size_t(msg.payloadlen);
if (i == transitions.size())
{
while (i--)
{
transitions[i].receptivity = (message[i] != '0');
}
}
else
{
m_messages.setError("MQTT: fire command length does not match number of transitions");
}
}, MQTT::QoS::QoS0);
}
#endif

//------------------------------------------------------------------------------
void Editor::showStyleSelector()
{
Expand Down
16 changes: 15 additions & 1 deletion src/Editor/DearImGui/Editor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,22 @@
# include "Utils/ForceDirected.hpp"
# include "Utils/History.hpp"
# include "Utils/Path.hpp"
# ifdef WITH_MQTT
# include "MQTT/MQTT.hpp"
# endif
# include <vector>

namespace tpne {

# ifndef WITH_MQTT
//! \brief Dummy MQTT class since disabled by the Makefile
class MQTT {};
# endif

// ****************************************************************************
//! \brief Graphical User interface for manipulating and simulating Petri net.
// ****************************************************************************
class Editor: public PetriNetEditor, public Application
class Editor: public PetriNetEditor, public Application, protected MQTT
{
public:

Expand All @@ -61,6 +69,12 @@ class Editor: public PetriNetEditor, public Application
virtual void onDraw() override;
void close();

#ifdef WITH_MQTT
private: // Inheritance from MQTT

virtual void onConnected(int rc) override;
#endif

private: // Widgets

void menu();
Expand Down
2 changes: 1 addition & 1 deletion src/julia/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ VPATH += $(P)/src/Net/Imports VPATH += $(P)/src/Net/Exports
###################################################
# Inform Makefile where to find header files
#
INCLUDES += $(P)/include $(P)/src $(P)/external
INCLUDES += $(P)/include $(P)/src

###################################################
# Internal libraries since we can call the GUI from Julia REPL
Expand Down

0 comments on commit 6578376

Please sign in to comment.