Skip to content

Files

Files in the station's own folders: configuration, alias files, state machines, media, extensions and logs. Only these folders are reachable, each by an id (its root).

Root Folder on a station Writable
config hw/config: boot.config, modules.config, log4net.config yes
alias hw/alias yes
fsms hw/fsms yes
media hw/capture yes
extensions hw/additional yes
logs hw/logs no
webapi-logs The WebApi's logs, audit.log among them no

A path is relative to its root, with forward slashes; "" is the root itself. A path that climbs out (..), names a drive or holds a character a file name can't is refused with 400, and a symbolic link anywhere below the root with 403. Changes in a read-only root raise 403. Changes are writes, so while another client holds the lease they raise 423.

Methods

Method Returns Description
get_roots() list[FileRoot] The folders the file API reaches.
list(root, path="") FileListing What a folder holds, folders first.
download(root, path) bytes A file's bytes. A log can be read while it is written.
upload(root, path, data, overwrite=False) FileEntry Upload a file (at most 64 MB). An existing file is replaced only with overwrite=True; 409 otherwise.
create_folder(root, path) — Create a folder; 409 if it exists.
move(root, source, target, overwrite=False) — Rename or move a file or folder within its root.
delete(root, path, recursive=False) — Delete a file, or a folder: an empty one, or one with contents with recursive=True (409 otherwise). The root itself can't be deleted.

An upload is written beside the old file first, so a failed upload leaves the old file as it was.

Examples

Browsing

for r in client.files.get_roots():
    print(f"{r.id:<12} writable={r.writable} exists={r.exists}  {r.description}")

listing = client.files.list("alias")
for e in listing.entries:
    kind = "dir " if e.directory else f"{e.size:>8}"
    print(f"{kind}  {e.modified}  {e.name}")

Backing Up and Restoring an Alias File

data = client.files.download("alias", "station.csv")
with open("station.csv", "wb") as fp:
    fp.write(data)

client.files.upload("alias", "station.csv", data, overwrite=True)

Folders, Moving and Deleting

client.files.create_folder("alias", "old")
client.files.move("alias", "limits.csv", "old/limits.csv")
client.files.delete("alias", "old", recursive=True)

Reading a Log

text = client.files.download("logs", "hw.log").decode("utf-8", errors="replace")
print(text[-2000:])

Loading an alias file into the hardware app is still client.application.load_config_file(name); to load it at every start, see boot.config.

Models

FileRoot

Field Type Description
id str The root id, e.g. alias
description str What the folder holds
writable bool Changes are allowed
exists bool False when the station doesn't have the folder

FileListing

Field Type Description
root str The root listed
path str The folder listed, relative to the root
writable bool Changes are allowed
entries tuple[FileEntry, ...] Its contents, folders first

FileEntry

Field Type Description
name str File or folder name
directory bool True for a folder
size int or None Bytes; None for a folder
modified str Last written (ISO 8601)