github.com/simpleiot/simpleiot@v0.18.3/api/client.go (about)

     1  package api
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"io"
     8  	"log"
     9  	"net/http"
    10  	"time"
    11  
    12  	"github.com/simpleiot/simpleiot/data"
    13  )
    14  
    15  // Point is a custom value of data.Point with Time set to a pointer. This allows
    16  // omitempty to work for zero timestamps to avoid bloating JSON packets.
    17  type Point struct {
    18  	// Type of point (voltage, current, key, etc)
    19  	Type string `json:"type,omitempty" influx:"type,tag"`
    20  
    21  	// Key of the device that provided the point
    22  	Key string `json:"key,omitempty" influx:"key,tag"`
    23  
    24  	// Average OR
    25  	// Instantaneous analog or digital value of the point.
    26  	// 0 and 1 are used to represent digital values
    27  	Value float64 `json:"value,omitempty" influx:"value"`
    28  
    29  	// Time the point was taken
    30  	Time *time.Time `json:"time,omitempty" gob:"-" influx:"time"`
    31  
    32  	// Duration over which the point was taken
    33  	Duration time.Duration `json:"duration,omitempty" influx:"duration"`
    34  }
    35  
    36  // NewPoint converts a data.Point to Point and rounds floating point
    37  // values to 3 dec places.
    38  func NewPoint(s data.Point) Point {
    39  	var time *time.Time
    40  
    41  	if !s.Time.IsZero() {
    42  		time = &s.Time
    43  	}
    44  
    45  	return Point{
    46  		Type:  s.Type,
    47  		Key:   s.Key,
    48  		Value: s.Value,
    49  		Time:  time,
    50  	}
    51  }
    52  
    53  // NewPoints converts []data.Sample to []Sample
    54  func NewPoints(points []data.Point) []Point {
    55  	ret := make([]Point, len(points))
    56  
    57  	for i, p := range points {
    58  		ret[i] = NewPoint(p)
    59  	}
    60  
    61  	return ret
    62  }
    63  
    64  // NewSendPoints returns a function that can be used to send points
    65  // to a SimpleIoT portal instance
    66  func NewSendPoints(portalURL, deviceID, authToken string, timeout time.Duration, debug bool) func(data.Points) error {
    67  	var netClient = &http.Client{
    68  		Timeout: timeout,
    69  	}
    70  
    71  	return func(points data.Points) error {
    72  		pointURL := portalURL + "/v1/devices/" + deviceID + "/points"
    73  
    74  		tempJSON, err := json.Marshal(NewPoints(points))
    75  		if err != nil {
    76  			return err
    77  		}
    78  
    79  		if debug {
    80  			log.Println("Sending points:", string(tempJSON))
    81  		}
    82  
    83  		req, err := http.NewRequest("POST", pointURL, bytes.NewBuffer(tempJSON))
    84  		if err != nil {
    85  			return err
    86  		}
    87  
    88  		req.Header.Set("Content-Type", "application/json")
    89  		req.Header.Set("Authorization", authToken)
    90  		resp, err := netClient.Do(req)
    91  
    92  		if err != nil {
    93  			return err
    94  		}
    95  
    96  		defer resp.Body.Close()
    97  
    98  		if resp.StatusCode != http.StatusOK {
    99  			errstring := "Server error: " + resp.Status + " " + pointURL
   100  			body, _ := io.ReadAll(resp.Body)
   101  			errstring += " " + string(body)
   102  			return errors.New(errstring)
   103  		}
   104  
   105  		return nil
   106  	}
   107  }