Writing file into File Manager with its custom app

I'm not expert in programming, but I like to do it for fun, it's like a puzzle!

So I've started to write my own app for efficiency purpose, since some of my somewhat complicated RM were a significant load for my hub. By writing dedicated custom apps, it reduces significantly the time spend to do the job in comparison to an equivalent RM as mentioned here: Writing your own "rule" apps worth it?

One of my RM is logging information into a txt file for further analysis with another computer. However, for what I understand, it is not currently possible to write local file into the hub with custom app since java.io.File cannot be imported. I'm sure this is for security reason.

Another nice guy has developed a way around: [BETA] Hubitat File Driver (HFD) but it still not solves my problem, since this method is based on a RM to write the file. The RM that I want to replace is currently a significant load for my hub.

So, my request/question, could it be possible to allow custom app to write file only into the File Manager? Although not mandatory, it will be a nice to have!

Just to clarify, in no way I want to diminish the RM app, it is super impressive all of the thing that we can do with it.

1 Like

Yep I asked that question a while ago.. since then have moved on to Node-RED which is an opensource visual flow control system originally written by IBM. It's a very cool way of writing rules and definitely lessens the overhead on my hubs (have 3). My NR is currently running on an RPi4 along with HomeBridge for Apple Homekit Integration.

1 Like

Thanks, node red is surely great alternative. I'm already using it for the broadlink universal remote and bluelinky for my Kia car and create custom driver has virtual device to communicate with Node red. However, when possible, I find it more efficient to run every thing on a single machine.

But if no plan to allow writing file within custom app, I will probably move those RM to node red.

I've never identied with something so hard
Spider-Man Reaction GIF

1 Like

The Hubigraph community app has been using file storage for its long term storage. It might be possible to figure out how it’s done by looking at its code. (The original developer left the platform some months back.)

1 Like

He did it the same way I did it in HPM (we actually talked about it a lot to figure it out). But basically it emulates going to the file manager page and clicking the buttons. The limitations are you can only do text based files, not binary, and if you have hub security on you will need to enter your username and password in the app so it can login as you. I wish they'd add an API, I've asked for it too, it would let me fix a long standing bug in HPM with file manager, but it doesn't seem high on the priority list.

4 Likes

I looked at it the other day and extracted the code and made it more generic

Local File Code
HashMap securityLogin(){
    def result = false
    try{
        httpPost(
				[
					uri: "http://127.0.0.1:8080",
					path: "/login",
					query: 
					[
						loginRedirect: "/"
					],
					body:
					[
						username: username,
						password: password,
						submit: "Login"
					],
					textParser: true,
					ignoreSSLIssues: true
				]
		)
		{ resp ->
//			log.debug resp.data?.text
				if (resp.data?.text?.contains("The login information you supplied was incorrect."))
					result = false
				else {
					cookie = resp?.headers?.'Set-Cookie'?.split(';')?.getAt(0)
					result = true
		    	}
		}
    }catch (e){
			log.error "Error logging in: ${e}"
			result = false
            cookie = null
    }
	return [result: result, cookie: cookie]
}


Boolean fileExists(fName){

    uri = "http://${location.hub.localIP}:8080/local/${fName}";

     def params = [
        uri: uri
    ]

    try {
        httpGet(params) { resp ->
            if (resp != null){
                return true;
            } else {
                return false;
            }
        }
    } catch (exception){
        if (exception.message == "Not Found"){
            log.debug("File DOES NOT Exists for $fName)");
        } else {
            log.error("Find file $fName) :: Connection Exception: ${exception.message}");
        }
        return false;
    }

}

String readFile(fName){
    if(security) cookie = securityLogin().cookie
    uri = "http://${location.hub.localIP}:8080/local/${fName}"

    def params = [
        uri: uri,
        contentType: "text/html; charset=UTF-8",
        headers: [
				"Cookie": cookie
            ]
    ]

    try {
        httpGet(params) { resp ->
            if(resp!= null) {
               data = resp.getData();           
               return data.toString()
            }
            else {
                log.error "Null Response"
            }
        }
    } catch (exception) {
        log.error "Read Error: ${exception.message}"
        return null;
    }
}



Boolean appendFile(fName,newData){
    try {
        fileData = readFile(fName)
        fileData = fileData.substring(0,fileData.length()-1)
        return writeFile(fName,fileData+newData)
    } catch (exception){
        if (exception.message == "Not Found"){
            return writeFile(fName, newData)      
        } else {
            log.error("Append $fName Exception: ${exception}")
            return false
        }
    }
}

Boolean writeFile(fName, fData) {
    if(security) cookie = securityLogin().cookie
	try
	{
		def params = [
			uri: "http://127.0.0.1:8080",
			path: "/hub/fileManager/upload",
			query: [
				"folder": "/"
			],
			headers: [
				"Cookie": cookie,
				"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryDtoO2QfPwfhTjOuS"
			],
			body: """------WebKitFormBoundaryDtoO2QfPwfhTjOuS
Content-Disposition: form-data; name="uploadFile"; filename="${fName}"
Content-Type: text/plain

${fData}

------WebKitFormBoundaryDtoO2QfPwfhTjOuS
Content-Disposition: form-data; name="folder"


------WebKitFormBoundaryDtoO2QfPwfhTjOuS--""",
			timeout: 300,
			ignoreSSLIssues: true
		]
		httpPost(params) { resp ->	
		}
		return true
	}
	catch (e) {
		log.error "Error writing file $fName: ${e}"
	}
	return false
}

Edit: More up to date code at https://raw.githubusercontent.com/thebearmay/hubitat/main/libraries/localFileMethods.groovy

4 Likes

Thanks a lot! It is amazing how fast you were responding. I will look into the code shared and see how I could implement it.

1 Like