As you have learned, the Python script of your App runs in the isolated environment of a Docker container. The script created a file in the filesystem of that container, but then you went looking for the file in the filesystem of the UNO Q's primary Linux machine.
The container framework does provide a mechanism for sharing files between the container and the host machine:
The Arduino App framework automatically creates a bind mount for the folder of the App. This is mapped to the /app folder in the container. So any changes your App's script makes to files under that path in the container will be applied to the contents of the App's folder in the filesystem of the UNO Q's primary operating system. The reason that didn't happen from the code you wrote is because you wrote to a file not under the /app path in the container's filesystem.
Here is a simple demonstration script:
from arduino.app_utils import App
try:
with open("/app/foo.txt", "a", encoding="utf-8") as f:
f.write("Hello, world!")
print("Outside 'with': file closed?", f.closed)
except Exception as e:
print(f"Error appending to file: {e}")
App.run()
If you create an App and use that code in the Python script of the App, after you run the App you will find that a file named foo.txt was created in the root of the App's folder. Unfortunately the "Files" view in Arduino App Lab doesn't reflect changes to the contents of the App folder via external mechanisms, so you won't see the file appear in the "Files" view while the App is open. However, if you switch Arduino App Lab back to the "My Apps" view, then open the App once again (this forces Arduino App Lab to rescan the contents of the App folder), you will see the file.
Please be careful when working with the contents of the /app folder from your code. If your code was to accidentally delete, overwrite, or corrupt the contents of your App project files, this could result in the loss of work you have done on your project. For the sake of simplicity, I wrote the file directly to the root of the App folder in the demonstration code I shared above, but I would recommend instead using a dedicated subfolder under the App folder for any real projects in order to somewhat isolate the filesystem changes made by the App.
Thank you for these insights. This is promising. From what I read about containers and dockets, isolating app files makes a lot of sense. Containers were just starting to be applied when I retired several years ago, so I didn't get into them at all. However, I enjoy learning new techniques and programming patterns.
I intend to learn about CLI as an alternative to AppLab this weekend. Thanks for all your help. I appreciate the time you took to explain and ask questions.
Yes. The App folder is at the path with the following format:
/home/arduino/ArduinoApps/<App slug>
<App slug> is the name of the App, converted to lowercase, and with spaces replaced by -. You can obtain a list of all your Apps by running the following command:
arduino-app-cli app list
The slug is a component of the App ID, which is shown under the "ID" column in the command's output.
It shows all the apps' names. But what I have wanted to know is this:
Access the Blink LED app and then view --
Files/
python/main.py
sketch/sketch.ino
sketch/skec.yaml
@davycastle
How can the following simple app be implemented on UNO Q?
MCU will acquire signal at 1 sec interval from its ADC-Ch0. Total 10 samples will be recorded on the eMMC under file named adc.txt with time stamp against every sample. After that the data from the eMMC will appear on Serial Monitor for viewing.
RESOLVED. I finally got what I wanted: a text file I can "see" and which has (by way of cat ) the data sent to it. I used the fully qualified file name - /home/arduino/ArduinoApps/ (where slug is the apps name: append2file). I derived the name from the apps list.
That did not work. Monitor reported "file not found" errors.
Finally, considering that the container is putting everything in one place, I used only the file name. No preceding directory names.
When I checked back, the file appeared and it had the data I sent.
Thank you everyone for your help and suggestions. Now I am going to look into the CLI method of using the UNO Q. It may be more appropriate for my needs.
I think it is working now. I can "see" the file. Its contents are correct. All the information and input I got from you and others were invaluable. I feel that I have a better understanding of how AppLab works. As I indicated, using the fully qualified file name produced error messages. Using just the text file name did work. This implies that the containerization inherent to AppLab automatically puts things in the app's folder. I find that that makes sense. However, I'd like to learn more about Docker.
CLI is on my agenda for now. I've found some good resources for learning how to use it vis-a-vis UNO Q.
That's fine. But you started with an app in post #1 which should be made working. Correct? Your app is repeated below:
Sketch:
#include <Arduino_RouterBridge.h>
bool result = false;
void setup()
{
Bridge.begin();
Monitor.begin();
delay(5000);
Bridge.call("append_to_file", "/home/arduino/data.txt", "Hello from MCU").result(result);
if (result)
{
Monitor.println("Append successful");
}
else
{
Monitor.println("Append failed");
}
}
void loop()
{
delay(3000);
Bridge.call("append_to_file", "/home/arduino/data.txt", "Hello from MCU").result(result);
if (result)
{
Monitor.println("Append successful");
}
else
{
Monitor.println("Append failed");
}
}
Script:
from arduino.app_utils import App, Bridge
def append_to_file(filename: str, text: str):
"""Append text to a file on the Linux side."""
print(f"append to file routine")
try:
with open(filename, "a", encoding="utf-8") as f:
f.write(text + "\n")
print("Outside 'with': file closed?", f.closed) # Should be True
print(f"text written to {filename} {text}")
return True
except Exception as e:
print(f"Error appending to file: {e}")
return False
Bridge.provide("append_to_file", append_to_file)
def loop():
pass # No periodic work needed
App.run(user_loop=loop)
Good point. Looking at the code in post #1, if the file name alone is used (without the directory names) the code works. I get exactly what I'm looking for. Using the /home/arduino/ArduinoApps/append2file/data.txt doesn't work. My conclusion in regards to post #1 is to take what I've learned, remove the directory names, and use only the file name. I'd also conclude that the reason why it works has to do with AppLab's containerization. Granted, this is purely by observation of results. It isn't totally satisfying, but it is enough to go on and should help when I get more familiar with Docker and containers.
Not agreed. Pls, see the following demonstration using sketch of your post #1.
The MCU sends the message along with full path of the file. The result() method of Bridge.call() contains the return string -- Hello from MCU after reading from file.
You may run this application to get the following output on the Serial Monitor at MCU side.
Hello from MCU
Hello from MCU
Hello from MCU
Sketch:
#include <Arduino_RouterBridge.h>
String fileContent = "";
bool status = false;
unsigned long prMillis = millis();
void setup()
{
Bridge.begin();
Monitor.begin(1);
}
void loop()
{
int adcValue = analogRead(A0);
Bridge.call("write_to_file", "Hello from MCU", "/home/arduino/data.txt");
do
{
RpcCall rpc = Bridge.call("read_from_file", "/home/arduino/data.txt");
status = rpc.result(fileContent);
}
while(status != true && millis() - prMillis < 5000);
if(status == true )
{
status = false;
Monitor.println(fileContent); //shows: Hello from MCU
}
else
{
Monitor.println("Error: Failed to read file from eMMC.");
}
delay(3000);
}
Script:
import time
import os
from arduino.app_utils import *
def writeToFile(msg, FILE_PATH):
try:
with open(FILE_PATH, "w") as f:
f.write(msg)
#print("Data writing ok");
return True
except Exception as e:
print(f"Error writing to eMMC: {e}")
return False
def readFromFile(FILE_PATH):
print("Reading data from eMMC")
if not os.path.exists(FILE_PATH):
#print("Error")
return "Error: File does not exist yet."
try:
with open(FILE_PATH, "r") as f:
#print("No error")
fContent = f.read()
print(fContent)
return fContent #f.read()
except Exception as e:
return f"Error reading file from eMMC: {e}"
def main():
# Register the functions so the C++ sketch can call them
Bridge.provide("write_to_file", writeToFile)
Bridge.provide("read_from_file", readFromFile)
# Keep the script running to listen for RPC commands
while True:
time.sleep(1)
if __name__ == "__main__":
main()
Are you not reading my posts? I've explained exactly why it didn't work multiple times now. I even provided code that demonstrates it, and specified the exact change you would need to make to your code.
Hi, I just guess, but it looks like python code not create file in home folder. The catch can be the application docker container not have access to Arduino user home.
Hi @milanriha. There is no need to guess. I already explained the problem in detail in post #21.
If you are interested in this subject, please read that post. If anything is unclear to you, or if you try the demonstration code I provided there and encounter a problem, just let us know and we'll see if we can assist you further.