skeleton
This commit is contained in:
parent
10c36bc30c
commit
9d138b0045
@ -10,9 +10,50 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
set(BOOST_ROOT /usr/local)
|
||||
find_package(Boost REQUIRED COMPONENTS system json)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
# Create a Boost-style interface target for a header-only library
|
||||
function(create_boost_header_only_target target_name)
|
||||
string(TOLOWER ${target_name} target_key)
|
||||
set(interface_target ${target_key}_interface)
|
||||
set(header_subdir ${target_key})
|
||||
|
||||
if(NOT TARGET Boost::${target_name})
|
||||
message(STATUS "Creating Boost::${target_name} as header-only interface target")
|
||||
|
||||
add_library(${interface_target} INTERFACE)
|
||||
|
||||
# Add include dir if not explicitly set
|
||||
if(DEFINED Boost_INCLUDE_DIRS)
|
||||
target_include_directories(${interface_target} INTERFACE ${Boost_INCLUDE_DIRS})
|
||||
else()
|
||||
message(WARNING "Boost_INCLUDE_DIRS not defined when creating Boost::${target_name}")
|
||||
endif()
|
||||
|
||||
# Optional preprocessor tweaks per library
|
||||
if(${target_name} STREQUAL "asio")
|
||||
target_compile_definitions(${interface_target} INTERFACE BOOST_ASIO_NO_DEPRECATED)
|
||||
endif()
|
||||
|
||||
# Create alias for consistency with imported targets
|
||||
add_library(Boost::${target_name} ALIAS ${interface_target})
|
||||
else()
|
||||
message(STATUS "Boost::${target_name} already exists")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
create_boost_header_only_target(asio)
|
||||
create_boost_header_only_target(assert)
|
||||
create_boost_header_only_target(core)
|
||||
create_boost_header_only_target(endian)
|
||||
create_boost_header_only_target(fusion)
|
||||
create_boost_header_only_target(optional)
|
||||
create_boost_header_only_target(random)
|
||||
create_boost_header_only_target(range)
|
||||
create_boost_header_only_target(smart_ptr)
|
||||
create_boost_header_only_target(spirit)
|
||||
create_boost_header_only_target(type_traits)
|
||||
|
||||
# spdlog
|
||||
FetchContent_Declare(
|
||||
spdlog
|
||||
@ -45,4 +86,4 @@ set(MQTT_BUILD_EXAMPLES OFF)
|
||||
set(async-mqtt5_INCLUDES_WITH_SYSTEM OFF)
|
||||
FetchContent_MakeAvailable(asyncmqtt5)
|
||||
|
||||
add_subdirectory(floorheat_hub)
|
||||
add_subdirectory(services)
|
||||
|
||||
@ -1,88 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "ACPowerInternal.proto";
|
||||
|
||||
package acpowercontrol;
|
||||
|
||||
message Error{
|
||||
///todo change to enum
|
||||
string details = 1;
|
||||
}
|
||||
|
||||
message ResetWatchdodRequest {
|
||||
uint32 channel = 1;
|
||||
}
|
||||
|
||||
message ResetWatchdodResponse {
|
||||
uint32 channel = 1;
|
||||
optional Error error = 2;
|
||||
}
|
||||
|
||||
// Main control message that can include one of the above actions
|
||||
message SetChannelRequest {
|
||||
uint32 channel = 1;
|
||||
oneof power {
|
||||
acpowercontrol.internal.ACPowerSwitchBinary switch = 2;
|
||||
acpowercontrol.internal.ACPowerToggle toggle = 3;
|
||||
acpowercontrol.internal.ACPowerModulation modulation = 4;
|
||||
acpowercontrol.internal.ACPowerSwipe swipe = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message SetChannelResponse {
|
||||
uint32 channel = 1;
|
||||
optional Error error = 2;
|
||||
}
|
||||
|
||||
message GetChannelRequest {
|
||||
uint32 channel = 1;
|
||||
}
|
||||
|
||||
message GetChannelResponse{
|
||||
uint32 channel = 1;
|
||||
oneof resp{
|
||||
uint32 current_power = 2;
|
||||
Error error = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message SetChannelConfigRequest {
|
||||
uint32 channel = 1;
|
||||
acpowercontrol.internal.ChannelConfig config = 2;
|
||||
}
|
||||
|
||||
message SetChannelConfigResponse {
|
||||
uint32 channel = 1;
|
||||
optional Error error = 2;
|
||||
}
|
||||
|
||||
message GetChannelConfigRequest {
|
||||
uint32 channel = 1;
|
||||
}
|
||||
|
||||
message GetChannelConfigResponse {
|
||||
uint32 channel = 1;
|
||||
oneof resp {
|
||||
acpowercontrol.internal.ChannelConfig config = 2;
|
||||
Error error = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message ACPower{
|
||||
oneof data{
|
||||
ResetWatchdodRequest reset_wtchdod_request= 1;
|
||||
ResetWatchdodResponse reset_wtchdod_response= 2;
|
||||
|
||||
SetChannelRequest set_channel_request = 3;
|
||||
SetChannelResponse set_channel_response = 4;
|
||||
|
||||
GetChannelRequest get_channel_request = 5;
|
||||
GetChannelResponse get_channel_response = 6;
|
||||
|
||||
SetChannelConfigRequest set_channel_config_request = 7;
|
||||
SetChannelConfigResponse set_channel_config_response= 8;
|
||||
|
||||
GetChannelConfigRequest get_channel_config_request = 9;
|
||||
GetChannelConfigResponse get_channel_config_response = 10;
|
||||
}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package acpowercontrol.internal;
|
||||
|
||||
// channel configuration
|
||||
message ChannelConfig{
|
||||
uint32 faze_nr = 1;
|
||||
uint32 default_watchdog_s = 2;
|
||||
}
|
||||
|
||||
// Message to represent basic on/off control
|
||||
message ACPowerSwitchBinary {
|
||||
bool on = 1;
|
||||
}
|
||||
|
||||
// Message to represent power toggle
|
||||
message ACPowerToggle {
|
||||
}
|
||||
|
||||
// Message to represent AC phase control (e.g., 30% of sine wave)
|
||||
message ACPowerModulation {
|
||||
// Phase percentage in i/10 of percent (value 123 rtanslates to 12.3%, typically 100.0)
|
||||
uint32 phase_percentage = 1;
|
||||
|
||||
// number of sinusoids taken to control (2 is a full sinus cycle, default 1)
|
||||
optional uint32 phaseGroup = 3; // if not present, assumed 1
|
||||
}
|
||||
|
||||
// Message to represent a soft start
|
||||
message ACPowerSwipe {
|
||||
enum Function{
|
||||
Linear = 0;
|
||||
Quadratic = 1; // Power increases exponentially over time, starting slow and speeding up.
|
||||
Logarithmic = 2; // Power increases logarithmically, starting fast and slowing down as it approaches the end.
|
||||
EaseInOut = 3; // This function starts and ends smoothly with a rapid change in the middle.
|
||||
}
|
||||
// Start percentage in i/10 of percent (value 123 rtanslates to 12.3%, typically 100.0)
|
||||
optional uint32 start_percentage = 1;
|
||||
|
||||
// End percentage in i/10 of percent (value 123 rtanslates to 12.3%, typically 100.0)
|
||||
uint32 end_percentage = 3;
|
||||
|
||||
// Duration in milliseconds
|
||||
uint32 duration_ms = 5;
|
||||
|
||||
// function used
|
||||
Function function=6;
|
||||
}
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
message FixedPoint {
|
||||
int32 integer_part = 1;
|
||||
uint32 fractional_part = 2;
|
||||
}
|
||||
|
||||
message x {
|
||||
uint32 ch = 1;
|
||||
bool state = 2;
|
||||
}
|
||||
|
||||
message FloatingPoint{
|
||||
float val = 2;
|
||||
}
|
||||
message SingleFazeData {
|
||||
float Voltage = 1;
|
||||
float Current = 2;
|
||||
float ActivePower = 3;
|
||||
float ApparentPower = 4;
|
||||
float PowerFactor = 5;
|
||||
float ReActivePower = 6;
|
||||
}
|
||||
|
||||
message EnergymeterSensorData {
|
||||
int32 sensor_id = 1;
|
||||
SingleFazeData L1 = 2;
|
||||
SingleFazeData L2 = 3;
|
||||
SingleFazeData L3 = 4;
|
||||
float TotalActivePower = 5;
|
||||
float TotalPowerFactor = 6;
|
||||
float TotalApparentePower = 7;
|
||||
float TotalReActivePower = 8;
|
||||
float GridFrequency = 9;
|
||||
}
|
||||
|
||||
message can_frame {
|
||||
uint32 left = 1;
|
||||
bytes data = 2;
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
|
||||
// internal
|
||||
// channel configuration
|
||||
message ChannelConfig{
|
||||
uint32 faze = 1;
|
||||
uint32 default_watchdog_s = 2;
|
||||
|
||||
}
|
||||
|
||||
// Message to represent basic on/off control
|
||||
message ACPowerBinary {
|
||||
bool on = 1;
|
||||
}
|
||||
|
||||
// Message to represent power toggle
|
||||
message ACPowerToggle {}
|
||||
|
||||
// Message to represent AC phase control (e.g., 30% of sine wave)
|
||||
message ACPowerProcentage {
|
||||
// Phase percentage from 0 to 100
|
||||
uint32 phase_percentage = 1;
|
||||
uint32 phase_percentageFraction = 2;
|
||||
|
||||
// number of sinusoids taken to control (2 is a full sinus cycle, default 1)
|
||||
optional uint32 phaseGroup = 3; // if not present, assumed 1
|
||||
}
|
||||
|
||||
// Message to represent a soft start
|
||||
message ACPowerSwipe {
|
||||
enum Function{
|
||||
Linear = 0;
|
||||
Quadratic = 1; // Power increases exponentially over time, starting slow and speeding up.
|
||||
Logarithmic = 2; // Power increases logarithmically, starting fast and slowing down as it approaches the end.
|
||||
EaseInOut = 3; // This function starts and ends smoothly with a rapid change in the middle.
|
||||
}
|
||||
// Start percentage (typically 0)
|
||||
optional uint32 start_percentage = 1;
|
||||
// Start percentage fraction (as 1/100 part of percentage) (typically 0)
|
||||
uint32 start_percentage_fraction = 2;
|
||||
|
||||
// End percentage (typically 100)
|
||||
uint32 end_percentage = 3;
|
||||
// End percentage fraction (as 1/100 part of percentage) (typically 0)
|
||||
uint32 end_percentage_fraction = 4;
|
||||
|
||||
// Duration in milliseconds
|
||||
uint32 duration_ms = 5;
|
||||
|
||||
// function used
|
||||
Function function=6;
|
||||
}
|
||||
|
||||
message ACPowerControl{
|
||||
oneof control_type {
|
||||
ACPowerBinary binary = 5;
|
||||
ACPowerProcentage procentage = 6;
|
||||
ACPowerSwipe swipe = 7;
|
||||
ACPowerToggle toggle = 8; // revert previous action
|
||||
}
|
||||
}
|
||||
|
||||
message ACPowerResetWatchdod{
|
||||
repeated uint32 channel = 1;
|
||||
}
|
||||
|
||||
// Main control message that can include one of the above actions
|
||||
message SetACPowerChannelControl {
|
||||
uint32 channel = 1;
|
||||
|
||||
ACPowerControl power = 2;
|
||||
|
||||
// seconds after which output will be turned off (in case of lack of control messages) 0 -> uses default
|
||||
uint32 watchdog_s = 3;
|
||||
}
|
||||
|
||||
message GetAcPowerChannelControl {
|
||||
uint32 channel = 1;
|
||||
}
|
||||
|
||||
message SetACPowerChannelConfig {
|
||||
uint32 channel = 1;
|
||||
ChannelConfig config = 2;
|
||||
}
|
||||
|
||||
message GetACPowerChannelConfig {
|
||||
uint32 channel = 1;
|
||||
}
|
||||
|
||||
enum HeatingMessagesId{
|
||||
ACPowerResetWatchdodID = 0;
|
||||
|
||||
SetACPowerChannelControlID = 1;
|
||||
GetAcPowerChannelControlID = 2;
|
||||
SetACPowerChannelConfigID = 3;
|
||||
GetACPowerChannelConfigID = 4;
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// single part of message
|
||||
message Frame{
|
||||
// frames left, 0 for End Of Stream
|
||||
uint32 parts = 1; // parts left
|
||||
|
||||
// encapsulated message
|
||||
bytes data = 2;
|
||||
|
||||
// type of message being encapsulated,only one of parts need to contain this information
|
||||
uint32 type = 3;
|
||||
}
|
||||
|
||||
message PrintfArgument {
|
||||
oneof arg_type {
|
||||
int32 int_val = 1;
|
||||
float float_val = 2;
|
||||
double double_val = 3;
|
||||
string string_val = 4;
|
||||
bool bool_val = 5;
|
||||
bytes bytes_val = 6;
|
||||
}
|
||||
}
|
||||
|
||||
message PrintfMessage {
|
||||
string format_string = 1;
|
||||
uint32 severity = 2;
|
||||
repeated PrintfArgument arguments = 3;
|
||||
}
|
||||
1
services/CMakeLists.txt
Normal file
1
services/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(floorheat_hub)
|
||||
@ -1,10 +1,3 @@
|
||||
# protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS
|
||||
# ../proto/message.proto
|
||||
# ../proto/heating.proto
|
||||
# ../proto/ACPower.proto
|
||||
# ../proto/ACPowerInternal.proto
|
||||
# )
|
||||
|
||||
add_executable(ranczo-io_floorheating
|
||||
main.cpp
|
||||
heater.cpp
|
||||
@ -22,7 +15,7 @@ target_include_directories(ranczo-io_floorheating
|
||||
target_link_libraries(ranczo-io_floorheating
|
||||
PUBLIC
|
||||
# ${Protobuf_LIBRARIES}
|
||||
Async::MQTT5
|
||||
Boost::mqtt5
|
||||
Boost::system
|
||||
Boost::json
|
||||
spdlog::spdlog
|
||||
@ -2,6 +2,7 @@
|
||||
#include <boost/asio/associated_executor.hpp>
|
||||
#include <boost/asio/co_spawn.hpp>
|
||||
#include <boost/asio/detached.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/this_coro.hpp>
|
||||
#include <memory>
|
||||
#include <memory_resource>
|
||||
@ -131,7 +132,7 @@ boost::asio::awaitable<void> spawn(ranczo::AsyncMqttClient & c1){
|
||||
int main() {
|
||||
spdlog::set_level(spdlog::level::trace);
|
||||
std::vector< std::unique_ptr< ranczo::IHeater > > _heaters;
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::io_context io_service;
|
||||
|
||||
/// Strand powoduje ¿e zadania do niego przypisane zostaj± wykonane sekwencyjnie,
|
||||
/// get_executor pobrany z io_service nie daje takiej mo¿liwo¶ci i wtedy mo¿na wykonywaæ zadania równloegle
|
||||
@ -153,7 +154,9 @@ int main() {
|
||||
// xes.emplace_back(std::allocate_shared< X >(alloc, io_executor, 2, "home/utilityRoom/floor/temperature"));
|
||||
// xes.emplace_back(std::allocate_shared< X >(alloc, io_executor, 3, "home/wardrobe/floor/temperature"));
|
||||
|
||||
boost::asio::io_service::work work(io_service);
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work_guard =
|
||||
boost::asio::make_work_guard(io_service);
|
||||
|
||||
io_service.run();
|
||||
|
||||
return 0;
|
||||
@ -6,12 +6,12 @@
|
||||
#include <memory>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <async_mqtt5.hpp>
|
||||
#include <boost/mqtt5.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ranczo {
|
||||
constexpr auto use_nothrow_awaitable = boost::asio::as_tuple(boost::asio::use_awaitable);
|
||||
using client_type = async_mqtt5::mqtt_client< boost::asio::ip::tcp::socket >;
|
||||
using client_type = boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket >;
|
||||
|
||||
struct AsyncMqttClient::AsyncMqttClientImpl {
|
||||
const boost::asio::any_io_executor & _executor;
|
||||
@ -34,17 +34,17 @@ struct AsyncMqttClient::AsyncMqttClientImpl {
|
||||
|
||||
boost::asio::awaitable< bool > subscribe(std::string_view topic) {
|
||||
// Configure the request to subscribe to a Topic.
|
||||
async_mqtt5::subscribe_topic sub_topic = async_mqtt5::subscribe_topic{topic.data(),
|
||||
async_mqtt5::subscribe_options{
|
||||
async_mqtt5::qos_e::exactly_once, // All messages will arrive at QoS 2.
|
||||
async_mqtt5::no_local_e::no, // Forward message from Clients with same ID.
|
||||
async_mqtt5::retain_as_published_e::retain, // Keep the original RETAIN flag.
|
||||
async_mqtt5::retain_handling_e::send // Send retained messages when the subscription is established.
|
||||
boost::mqtt5::subscribe_topic sub_topic = boost::mqtt5::subscribe_topic{topic.data(),
|
||||
boost::mqtt5::subscribe_options{
|
||||
boost::mqtt5::qos_e::exactly_once, // All messages will arrive at QoS 2.
|
||||
boost::mqtt5::no_local_e::no, // Forward message from Clients with same ID.
|
||||
boost::mqtt5::retain_as_published_e::retain, // Keep the original RETAIN flag.
|
||||
boost::mqtt5::retain_handling_e::send // Send retained messages when the subscription is established.
|
||||
}};
|
||||
|
||||
// Subscribe to a single Topic.
|
||||
auto && [ec, sub_codes, sub_props] =
|
||||
co_await _mqtt_client.async_subscribe(sub_topic, async_mqtt5::subscribe_props{}, use_nothrow_awaitable);
|
||||
co_await _mqtt_client.async_subscribe(sub_topic, boost::mqtt5::subscribe_props{}, use_nothrow_awaitable);
|
||||
// Note: you can subscribe to multiple Topics in one mqtt_client::async_subscribe call.
|
||||
|
||||
// An error can occur as a result of:
|
||||
@ -65,7 +65,7 @@ struct AsyncMqttClient::AsyncMqttClientImpl {
|
||||
// Receive an Appplication Message from the subscribed Topic(s).
|
||||
auto && [ec, topic, payload, publish_props] = co_await _mqtt_client.async_receive(use_nothrow_awaitable);
|
||||
|
||||
if(ec == async_mqtt5::client::error::session_expired) {
|
||||
if(ec == boost::mqtt5::client::error::session_expired) {
|
||||
/// TODO connect first, then subscribe to all topics
|
||||
// The Client has reconnected, and the prior session has expired.
|
||||
// As a result, any previous subscriptions have been lost and must be reinstated.
|
||||
Loading…
Reference in New Issue
Block a user