Software Design Explanation
Software framework#
Software Design Diagram#

UML#

System startup process#

- Instantiate application objects
- Import configuration JSON file
- Initialize various application extension components (this step will register each application extension into the main application object, facilitating communication between extensions)
- Check the network (this step will block waiting for the network to be ready. If the wait times out, try switching to cfun to restore the network)
- Load application extensions and start related services (customizable by users)
- The system enters normal operation mode (by default, SIM card and network detection are enabled. If there is a network failure, it will attempt to switch to cfun to restore the network)
Implement#
Sequence Diagram#
Code Catalog#
The code for the smart meter solution is hosted on Github The directory structure of the code is as follows:
Basic framework#
The smart meter solution is developed based on an application framework called QFrame.
The
QFrame
application framework is a fundamental application framework developed by QuecPython. Click here to view Design and application guidance for this framework.
An application often relies on multiple business modules, and there may be coupling between them.
In the framework design, the communication between business modules adopts a star shaped structure design, as shown in the following figure:
The Mediator in the figure is an intermediary object (usually named 'Application') that communicates between various business modules through the Application
object. This design is called the intermediary pattern.
The business module is embedded in the application program in the form of application extensions, and the interaction between various application extensions is uniformly scheduled through the Application
object.
Application objects and extensions#
Applications based on the QFrame framework must have a central object for scheduling various business modules, namely the Application object mentioned earlier; The application parameters are also configured through this object.
example:
Application
class:
Definition and initialization of application extension#
Application extension refers to the business modules loaded by the Application
object. Generally speaking, application extensions obtain their own configuration from app.config
and pass it to the application instance during initialization.
The use of application extension includes two parts: definition and initialization. Application extension provides a base class called AppExtendeABC
, defined as follows:
This base class is inherited by a specific application extension class to constrain the interface definition of the application extension class.
- We need to pass the
Application
application object to the initialization method__init__
. When creating an application extension object, callinit_app
to complete the initialization action of the extension; It is also possible to create an application extension object directly without passing in the application object, and then explicitly callinit_app
to complete initialization. - The
load
method is used to be called by theApplication
object to load various application extensions.
The use of application expansion#
When the application extension inherits the base class AppExtendeABC
and implements the necessary interface functions, you can refer to the following two different ways of code to load the application extension object.
Method 1:
Method 2:
Main Application#
As the script file for application entry, demo.py
provides a factory function create_app
that passes in the configuration path to initialize the application and load various application extensions.
demo.py
sample code is as follows:
Application Extensions#
The main application extension functions include three main categories rfc1662resolver
(1662 protocol resolution), client
(tcp client) and uart
(serial read and write), which are all registered in the application object Application
for ease of coordination.
rfc1662resolver
: responsible for parsing and assembling RFC1662 protocol messages, (RFC1662ProtocolResolver
instance object).client
: tcp client (BusinessClient
instance object), responsible for communicating with the tcp server.uart
: serial port client (UartBusiness
instance object), responsible for serial read and write.
Class RFC1662ProtocolResolver
#
This class is an application extension class, an RFC1662 protocol data resolver, used to process RFC1662 protocol data transmitted in the business, and pack and unpack this class data.
The class provides the following methods:
- resolve(msg)
- Function: Process an RFC1662 protocol message. The behavior is to find the processing function of the message from the registry by resolving the protocol (which can be understood as the message id of the protocol message), and call the function to process if found, otherwise throw a
ValueError
exception. See theregister
decorator function on how to register the processing function. - Parameters:
msg
is anRFC1662Protocol
object, which is an encapsulation class of the RFC1662 protocol, see the introduction below. - Return value: None
- Exceptions: If the processing function cannot be found in the registry for the incoming
msg
, aValueError
exception will be thrown.
- Function: Process an RFC1662 protocol message. The behavior is to find the processing function of the message from the registry by resolving the protocol (which can be understood as the message id of the protocol message), and call the function to process if found, otherwise throw a
- register(protocol)
- Function: It is a decorator function used to register a processing function for a protocol.
- Parameters:
protocol
can be understood as the message id of the RFC1662 protocol. - Return value: original function
- tcp_to_meter_packet(data)
- Function: Static method, pack the byte data
data
into a transparent RFC1662 data packet (0x2100), that is, the data frame passed to the meter by tcp transparent transmission. - Parameters:
data
, byte type. - Return value: 0x2100 protocol packet byte string
- Exceptions: None
- Function: Static method, pack the byte data
- module_to_meter_packet(data)
- Function: Static method, assemble RFC1662 protocol data packet (0x2200), that is, the data frame sent by the module to the meter
- Parameters: data is a list, [get/set, id, data], where:
get/set
:COSEM.GET/COSEM.SET
, the corresponding values are0xC0/0xC1
respectivelyid
: function command worddata
: byte type
- Return value: 0x2200 protocol packet byte string
Sample code:
Class RFC1662Protocol
#
This class is a specific implementation of the RFC1662 protocol, including unpacking and packing. The instance object of this class is an encapsulated form of a complete RFC1662 protocol package. The main methods are:
build_rfc_0x2100
: assemble 0x2100 protocol packet, return bytes, equivalent toRFC1662ProtocolResolver.tcp_to_meter_packet
build_rfc_0x2200
: assemble 0x2200 protocol packet, return bytes, equivalent toRFC1662ProtocolResolver.module_to_meter_packet
build
: class method, used to resolve a protocol packet frame, returnRFC1662Protocol
object.replay_get
: reply get command, judge success or failurereplay_set
: reply set commandreply_event
: reply event information
TCP Client Component#
Base Class TcpClient
#
This class exposes two interfaces to the user:
recv_callback
method, users rewrite this method to achieve business processing of TCP server downlink data.send
method, users can call this method to send data to the server.
Code is as follows:
Subclass BusinessClient
#
BusinessClient
rewrites the recv_callback
method to encapsulate the downlink data of the server into RFC1662 format messages and forwards the data to the serial port.
Code is as follows:
Serial Communication Component#
Base Class Uart
#
This class exposes two interfaces to users:
recv_callback
method, users rewrite this method to achieve business processing of received serial data.send
method, users can call this method to send data to the serial port.
Code is as follows:
Subclass UartBusiness
#
UartBusiness
rewrites the recv_callback
method to implement business processing of received serial data.
In the subclass
UartBusiness
'srecv_callback
method, after parsing the RFC1662 protocol message, constructing the message object, distribute the message processing business through therfc1662resolver.resolve
method.
Writing Business Programs#
Define a global rfc1662resolver
resolver in the script file business.py
to register message processing functions of specified types.
The following sample code registers the 0x2100 protocol transparent transfer processing function: