Matlab/Simulink: How to receive MATLAB commands via HTTP GET request

This example shows how to receive MATLAB commands via HTTP GET request.

In our previous example Matlab TCP/IP command server without any toolboxes we showed how to create a TCP/IP server in MATLAB without resorting to toolbox-only commands. However, even when being run using a Matlab Timer, it will block the GUI completely since Matlab inherently runs in a single-threaded way.

In this example, we’ll use a different strategy: Matlab itself is commanded via a Timer to periodically issue a HTTP request to an external Webserver. The webserver will then respond with a command to be executed in Matlab.

In this example, there is no feedback whatsoever on the output of the command!

Main MATLAB request function

function http_command()
    % Function to execute MATLAB commands received via HTTP
    
    try
        % URL for the HTTP request
        url = 'http://127.0.0.1:17231/command';
        
        % Send HTTP request and receive response
        options = weboptions('Timeout', 0.1, 'ContentType', 'text');
        response = webread(url, options);
        
        % Check status code (webread throws an exception for non-200 responses)
        % If we're here, the status code was 200
        
        % Check if the response is not empty
        if ~isempty(response)
            % Split response into lines
            commandLines = strsplit(response, '\n');
            
            % Execute each line as a MATLAB command
            for i = 1:length(commandLines)
                commandLine = strtrim(commandLines{i});
                
                % Skip empty lines
                if ~isempty(commandLine)
                    try
                        disp(['Executing command: ', commandLine]);
                        evalc(commandLine); % evalc suppresses standard output
                    catch cmdError
                        warning('Error executing command "%s": %s', ...
                                commandLine, cmdError.message);
                    end
                end
            end
        else
            disp('Empty response received from server.');
        end
        
    catch httpError
        % Error handling for HTTP errors
        if contains(httpError.message, '404')
            disp('HTTP 404: Resource not found.');
        elseif contains(httpError.message, '500')
            disp('HTTP 500: Server error.');
        elseif contains(httpError.message, 'Connection')
            disp('Connection error: Server possibly not reachable.');
        else
            disp(['HTTP error: ', httpError.message]);
        end
    end
end

MATLAB Timer

function http_command_timer()
  % Creates a timer that calls executeHttpCommands() every 0.5 seconds
  
  % If a timer with this name already exists, delete it
  existingTimer = timerfind('Name', 'HttpCommandTimer');
  if ~isempty(existingTimer)
    stop(existingTimer);
    delete(existingTimer);
    disp('Existing timer was stopped and deleted.');
  end
  
  % Create new timer
  t = timer('Name', 'HttpCommandTimer', ...
        'Period', 0.5, ...             % Timer interval (0.5 seconds)
        'ExecutionMode', 'fixedRate', ... % Fixed repeat rate
        'TimerFcn', @(~,~)http_command(), ... % Function to be called
        'ErrorFcn', @(~,~)disp('Error executing HTTP command'));
  
  % Start timer
  start(t);
  disp('HTTP Command Timer started. Calls executeHttpCommands() every 0.5 seconds.');
  disp('Use stopHttpCommandTimer() to stop the timer.');
end

Python server

This simple example server will issue commands to alternatingly switch on and off a manual switch.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from http.server import BaseHTTPRequestHandler, HTTPServer
import time

class CommandServer(BaseHTTPRequestHandler):
  # Class variable to track state
  toggle_state = False
  
  def do_GET(self):
    if self.path == '/command':
      # Prepare alternating command
      if CommandServer.toggle_state:
        command = "set_param('printit/Manual Switch', 'sw', '1');"
      else:
        command = "set_param('printit/Manual Switch', 'sw', '0');"
      
      # Toggle state for next request
      CommandServer.toggle_state = not CommandServer.toggle_state
      
      # Send HTTP response
      self.send_response(200)
      self.send_header('Content-type', 'text/plain')
      self.end_headers()
      self.wfile.write(command.encode('utf-8'))
      
      print(f"Command sent: {command}")
    else:
      # 404 error for all other paths
      self.send_response(404)
      self.send_header('Content-type', 'text/plain')
      self.end_headers()
      self.wfile.write(b'404 Not Found')

def run_server(port=17231):
  server_address = ('127.0.0.1', port)
  httpd = HTTPServer(server_address, CommandServer)
  print(f"Server running at http://127.0.0.1:{port}")
  print("Press Ctrl+C to stop")
  try:
    httpd.serve_forever()
  except KeyboardInterrupt:
    pass
  httpd.server_close()
  print("Server stopped")

if __name__ == '__main__':
  run_server()