I use this for logging from inside a rule, using an HTTP GET, for saving data from Maker API to disk on a Windows host.
I will probably add emailing to this app soon so I can send the files as attachments to IFTTT and have them save the attachment to Google drive, I imagine.
Here is the rule.
And the possibility of using the maker API to run real-time graphs and gauges like in Node-Red.
I'm working on a wee project 2 building an ERV system using my Hubitat, Arduino and Xiaomi.
Usage
HTTP call in rule machine
You can see how the above URL works ?csv=name of device 1, name of device 2
?csv=name of device 1, name of device 2
Makes the logger log a file on the Windows host for the whole day, and return all the rows currently in the file.
?json=name of device 1, name of device 2
Makes a log for the yyyy-MM-dd-hh-mm-ss
The file name is logNAME-yyyy-MM-dd.txtx for CSV data and logNAME-yyyy-MM-dd-hh-mm-ss.json for the JSON format.
As long as the call begins with log and has the .svs extension it will work.
if you use http://192.168.1.71:82/logtempertures.svs?json=Outside%20Climate, for example, you get back JSON
The JJSON with the current device value and is stored here, a new file for every second.
You need to set the Get All Devices URL e.g. http://192.168.1.65/apps/api/6/devices?access_token=???????????????????? to point to your Hub in App.Config
A JavaScript usage example
$.getJSON('http://192.168.1.71:82/logtempertures.svs?json=Outside%20Climate', function(json){ console.log(json[0].attributes) var val = json[0].attributes[6].currentValue; console.log(json[0].val) });
static void HTTPserver_SVSrequest(object o, HTTPrequest Request) { if (Request.Action != null) Console.WriteLine("Action: " + Request.Action.Trim()); if (Request.Args != null) Console.WriteLine("Post Args: " + Request.Args); if (Request.Action.Trim().ToLower().EndsWith(".svs")) { if (Request.Action.ToLower().StartsWith("log")) { JArray deviceJSON = new JArray(); //Request.RawURL //"/LogClimate.svs?ids=Hallway%20Climate,Outside%20Climate" string args = ""; if (Request.Method.Trim() == "POST") args = Request.Args.TrimEnd('#').Replace("%20", " "); else if (Request.Method.Trim() == "GET") args = Request.RawURL.Replace("%20", " "); string[] dlabs = args.Split('=')[1].Split(','); using (WebClient wc = new WebClient()) { string url = Settings.Default.GetAllDevicesURL; string sjson = wc.DownloadString(url); DeviceList = JArray.Parse(sjson); } string CSVline = DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss") + ","; //Each ID foreach (string dlab in dlabs) { //Find Device foreach (JObject jo in DeviceList) { /* { "id":"673", "name":"Xiaomi Temperature Humidity Sensor", "label":"Hallway Climate" }, */ if (jo["label"].ToString() == dlab) { string did = jo["id"].ToString(); CSVline += ("device," + dlab + ",ld," + did + ","); using (WebClient wc = new WebClient()) { //e.g. http://192.168.1.65/apps/api/6/devices/673?access_token=ae6f8845-6916-4b8a-a9b2-67f7f5261ef7 string url = string.Format("http://192.168.1.65/apps/api/6/devices/{0}?access_token=ae6f8845-6916-4b8a-a9b2-67f7f5261ef7", did); string sjson = wc.DownloadString(url); JObject jod = JObject.Parse(sjson); deviceJSON.Add(jod); /* "attributes":[ { "name":"battery", "currentValue":70, "dataType":"NUMBER" }, { "name":"batteryLastReplaced", "currentValue":"Jul 20 2020", "dataType":"STRING" }, { "name":"humidity", "currentValue":31.9, "dataType":"NUMBER" }, { "name":"lastCheckinEpoch", "currentValue":"1601591927215", "dataType":"STRING" }, { "name":"lastCheckinTime", "currentValue":"Oct 2, 2020 11:38:47 AM", "dataType":"DATE" }, { "name":"pressure", "currentValue":null, "dataType":"NUMBER" }, { "name":"temperature", "currentValue":23.79, "dataType":"NUMBER" } ], */ string rejectAttr = "lastCheckinTime,lastCheckinEpoch,batteryLastReplaced"; JArray attrs = JArray.Parse(jod["attributes"].ToString()); foreach(JObject attr in attrs) if(!rejectAttr.Contains(attr["name"].ToString()) ) CSVline += (attr["name"].ToString() + "," + attr["currentValue"].ToString() + ","); }//End of using (WebClient wc = new WebClient()) break;//Whole device done }//End of if (jo["label"].ToString() == dlab) }//End of foreach (JObject jo in DeviceList) }//End of foreach (string dlab in dlabs) CSVline = CSVline.TrimEnd(','); //WRITE AS JSON if (args.Contains("json")) { string folder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\json\"; if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); string file = folder + Request.Action.Replace("/", "\\") + "-" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + ".json"; string sjson = JsonConvert.SerializeObject(deviceJSON); File.WriteAllText(file, sjson); //Send back last value usefull HTTPserver.Response(sjson); } //WRITE AS CSV TEXT else if (args.Contains("csv")) { string folder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\data\"; if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); string file = folder + Request.Action.Replace("/", "\\") + "-" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt"; //Add this line File.AppendAllText(file, CSVline + "\r\n"); //Get whole file so far string CSVlines = File.ReadAllText(file); HTTPserver.Response(CSVlines); } }//End of if (Request.Action.ToLower().StartsWith("logclimate")) }//End of else if (Request.Action.Trim().ToLower().EndsWith(".svs")) }
Hubitat I may be missing something, but if not, when are you going to add some JSON handling into your marvellous product, please?