Announcement

Collapse
No announcement yet.

Any Plugin functions or Liquid Tags to download a file?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Any Plugin functions or Liquid Tags to download a file?

    I want to allow a plugin user to download a file, PDF, log file, etc.

    Anyone know how HST's web server works to allow a file download via browser?
    HS4Pro Running on a Raspberry Pi4
    67 Z-Wave Nodes, 111 Events, 422 Devices
    Z-Wave, UPB, WiFi
    Plugins: EasyTrigger, weatherXML, OMNI, Z-Wave, Tuya, Device History
    HSTouch Clients: 3 Android, 1 Joggler

    #2
    I was wondering if you found a solution for this. In my case, I want the user to be able to download a CSV file that my plugin generates.

    Here is what I came up with so far:

    1. Untested yet, but this should work, I guess:
    - Save file to the the plugin's html folder
    - Simply make a link to it in a feature page. A liquid tag could generate the file and create the link if it's different every time.
    - Delete file next time, to make sure the folder does not overflow.

    2. In (my) case of a text based file this seems to work:
    - Create a CSV file with a liquid tag
    - Use RegisterFeaturePage()* to register the CSV file, creating the link in the menu
    - When called, the CSV will be generated. User should be instructed to Save Page As from the browser, as most browser just open text files, I guess.

    3. This seems to work, too. Tested by placing an existing PDF in my plugin's html folder:
    - Save file to plugin's html folder (for example from a html page with a liquid tag)
    - Use RegisterFeaturePage()* to register the file. When the user clicks the link the file will be downloaded.
    - Use UnregisterFeaturePage() at some point (from the same html, or after a certain time) to remove the link again. Then delete the file.

    * Note: Documentation says: "The filename of the page, ending with .html", so if they ever decide to make it that strict, this will break.

    Comment


      #3
      To send the file to HS (upload) I asked a question on PluginSDK GitHub https://github.com/HomeSeer/Plugin-SDK/issues/156

      To get a file from HS (download) is probably more complicated because the user needs to browse the filesystem via browser? Try also asking on GitHub.

      Comment


        #4
        I found a workaround...

        The HS web server will only serve up files from the html folder, so you cant go back to the Config or Log folders, which makes sense from a security perspective.

        So, following HomeSeer's interface, I made a Labs page for my plugin. On that page, I can grab whatever I need from the plugin since it runs under the HS root folder. The user can click a button, then I just load up a textarea with the file contents and provide a 'Copy to Clipboard' function. It works well.

        Click image for larger version

Name:	screenshot1.png
Views:	103
Size:	66.6 KB
ID:	1531452

        The plugin code for View OMNI Logs is:

        Code:
        Public Function GetLogs() As String
        Dim response As String
        Try
        response = IO.File.ReadAllText(g_debugFile)
        If (response Is Nothing) Then
        response = "No logs found."
        End If
        Catch ex As Exception
        response = "Unable to get log file: " & g_debugFile & " " & ex.Message
        End Try
        Return response
        End Function
        HS4Pro Running on a Raspberry Pi4
        67 Z-Wave Nodes, 111 Events, 422 Devices
        Z-Wave, UPB, WiFi
        Plugins: EasyTrigger, weatherXML, OMNI, Z-Wave, Tuya, Device History
        HSTouch Clients: 3 Android, 1 Joggler

        Comment


          #5
          It seems the number of workarounds for generated text are endless.

          I just figured out the following, which seems to work. It can be done in an .aspx file, which can be linked from a html page, or called from a link created with RegisterFeaturePage().
          These are my first .aspx sources, so they may probably be done in different/better/smarter ways. Anyway, key is to be able to create headers.

          For an Excel file:

          Code:
          <%
          Response.ContentType = "application/x-msexcel"
          Response.AppendHeader("Content-Disposition", "attachment; filename=test.xlsx")
          Response.TransmitFile(Server.MapPath("~/MyPluginFolder/test.xlsx"))
          Response.End()
          %>
          For a PDF file (which may open in the browser if you have a reader installed, which is why I tried the Excel file too):

          Code:
          <%
          Response.ContentType = "application/pdf"
          Response.AppendHeader("Content-Disposition", "attachment; filename=test.pdf")
          Response.TransmitFile(Server.MapPath("~/MyPluginFolder/test.pdf"))
          Response.End()
          %>
          Which seems like a complicated way to create a link, but it gives you an opportunity to make things dynamic.

          --

          Edit: Forget the above. No need to dive into aspx. I ended up implementing it in javascript. The html for posts which data to generate and the response is the file data. So no file gets saved in the html folder.

          Code:
          var element = document.createElement('a');
          
          element.setAttribute('href', 'data:csv/plain;charset=utf-8,' + encodeURIComponent(response));
          element.setAttribute('download', "MyFile.csv");
          
          element.style.display = 'none';
          document.body.appendChild(element);
          
          element.click();
          
          document.body.removeChild(element);
          For a more complex file (pdf?) it may be needed to write the file to the html folder. It can then be downloaded in the following way (tested with manually placed pdf file in the html folder):

          Code:
          function downloadFile() {
          var filename = "MyFile.pdf";
          fetch(window.location.origin + "/MyPluginFolder/" + filename)
          .then(resp => resp.blob())
          .then(blob => {
          const url = window.URL.createObjectURL(blob);
          const element = document.createElement('a');
          element.style.display = 'none';
          element.href = url;
          element.download = filename; //Change if the name of the downloaded file should be different
          document.body.appendChild(element);
          element.click();
          window.URL.revokeObjectURL(url);
          //Done, file could be deleted
          alert('Your file should be downloaded.');
          })
          .catch(() => alert('Error while downloading file.'));
          }

          Comment

          Working...
          X