tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/examples/net/mqttclient/natiu/main.go (about)

     1  // This example is an MQTT client built with the natiu-mqtt package.  It sends
     2  // machine.CPUFrequency() readings to the broker every second for 10 seconds.
     3  //
     4  // Note: It may be necessary to increase the stack size when using
     5  // paho.mqtt.golang.  Use the -stack-size=4KB command line option.
     6  
     7  //go:build ninafw || wioterminal || challenger_rp2040
     8  
     9  package main
    10  
    11  import (
    12  	"context"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  	"log"
    17  	"machine"
    18  	"math/rand"
    19  	"net"
    20  	"time"
    21  
    22  	mqtt "github.com/soypat/natiu-mqtt"
    23  	"tinygo.org/x/drivers/netlink"
    24  	"tinygo.org/x/drivers/netlink/probe"
    25  )
    26  
    27  var (
    28  	ssid   string
    29  	pass   string
    30  	broker string = "test.mosquitto.org:1883"
    31  	topic  string = "cpu/freq"
    32  )
    33  
    34  func main() {
    35  	waitSerial()
    36  
    37  	link, _ := probe.Probe()
    38  
    39  	err := link.NetConnect(&netlink.ConnectParams{
    40  		Ssid:       ssid,
    41  		Passphrase: pass,
    42  	})
    43  	if err != nil {
    44  		log.Fatal(err)
    45  	}
    46  
    47  	clientId := "tinygo-client-" + randomString(10)
    48  	fmt.Printf("ClientId: %s\n", clientId)
    49  
    50  	// Get a transport for MQTT packets
    51  	fmt.Printf("Connecting to MQTT broker at %s\n", broker)
    52  	conn, err := net.Dial("tcp", broker)
    53  	if err != nil {
    54  		log.Fatal(err)
    55  	}
    56  	defer conn.Close()
    57  
    58  	// Create new client
    59  	client := mqtt.NewClient(mqtt.ClientConfig{
    60  		Decoder: mqtt.DecoderNoAlloc{make([]byte, 1500)},
    61  		OnPub: func(_ mqtt.Header, _ mqtt.VariablesPublish, r io.Reader) error {
    62  			message, _ := io.ReadAll(r)
    63  			fmt.Printf("Message %s received on topic %s\n", string(message), topic)
    64  			return nil
    65  		},
    66  	})
    67  
    68  	// Connect client
    69  	var varconn mqtt.VariablesConnect
    70  	varconn.SetDefaultMQTT([]byte(clientId))
    71  	ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
    72  	err = client.Connect(ctx, conn, &varconn)
    73  	if err != nil {
    74  		log.Fatal("failed to connect: ", err)
    75  	}
    76  
    77  	// Subscribe to topic
    78  	ctx, _ = context.WithTimeout(context.Background(), 10*time.Second)
    79  	err = client.Subscribe(ctx, mqtt.VariablesSubscribe{
    80  		PacketIdentifier: 23,
    81  		TopicFilters: []mqtt.SubscribeRequest{
    82  			{TopicFilter: []byte(topic), QoS: mqtt.QoS0},
    83  		},
    84  	})
    85  	if err != nil {
    86  		log.Fatal("failed to subscribe to", topic, err)
    87  	}
    88  	fmt.Printf("Subscribed to topic %s\n", topic)
    89  
    90  	// Publish on topic
    91  	pubFlags, _ := mqtt.NewPublishFlags(mqtt.QoS0, false, false)
    92  	pubVar := mqtt.VariablesPublish{
    93  		TopicName: []byte(topic),
    94  	}
    95  
    96  	for i := 0; i < 10; i++ {
    97  		if !client.IsConnected() {
    98  			log.Fatal("client disconnected: ", client.Err())
    99  		}
   100  
   101  		freq := float32(machine.CPUFrequency()) / 1000000
   102  		payload := fmt.Sprintf("%.02fMhz", freq)
   103  
   104  		pubVar.PacketIdentifier++
   105  		err = client.PublishPayload(pubFlags, pubVar, []byte(payload))
   106  		if err != nil {
   107  			log.Fatal("error transmitting message: ", err)
   108  		}
   109  
   110  		time.Sleep(time.Second)
   111  
   112  		conn.SetReadDeadline(time.Now().Add(10 * time.Second))
   113  		err = client.HandleNext()
   114  		if err != nil {
   115  			log.Fatal("handle next: ", err)
   116  		}
   117  
   118  	}
   119  
   120  	client.Disconnect(errors.New("disconnected gracefully"))
   121  
   122  	for {
   123  		select {}
   124  	}
   125  }
   126  
   127  // Returns an int >= min, < max
   128  func randomInt(min, max int) int {
   129  	return min + rand.Intn(max-min)
   130  }
   131  
   132  // Generate a random string of A-Z chars with len = l
   133  func randomString(len int) string {
   134  	bytes := make([]byte, len)
   135  	for i := 0; i < len; i++ {
   136  		bytes[i] = byte(randomInt(65, 90))
   137  	}
   138  	return string(bytes)
   139  }
   140  
   141  // Wait for user to open serial console
   142  func waitSerial() {
   143  	for !machine.Serial.DTR() {
   144  		time.Sleep(100 * time.Millisecond)
   145  	}
   146  }