The File object is the BACnet abstraction for a data file stored inside (or
accessible through) the device. It enables remote file transfer using the
BACnet.Protocol.Services.AtomicReadFile and BACnet.Protocol.Services.AtomicWriteFile
services. Clients first read the File object's properties to learn the file's
size, access method (stream or record), and last modification time, then perform
the actual transfer operations using the file's Object Identifier.
The object does not interpret the file contents; that is a local matter (firmware
image, configuration database, trend export, etc.). The file_access_method
property declares whether the file is accessed as a stream of octets or as a
sequence of records.
Object Description (ASHRAE 135)
The File object type defines a standardized object that is used to describe properties of data files that may be accessed using File Services.
Behaviour and Operation
File objects are descriptors for data files accessible via the AtomicReadFile,
AtomicWriteFile services. The local file system or virtual file handler is
responsible for keeping file_size, modification_date, and archive in sync
with the actual underlying storage.
Clients first read the File object to learn the access method (file_access_method)
and file_size, then issue file service requests using the object's identifier.
The actual transfer of octets or records is performed by the file services
implementation, not by the object itself. The object is a pure metadata container.
Developer Implementation Notes (geared to device server / application authors)
The generated code handles storage + basic mechanics (validation, implicit_relationships,
readonly annotations as hints to your server, etc.). You must drive "special" live
properties and side effects yourself, via update_property/3 (never direct mutation).
Read notes below + generated tables for details.
Special / live properties and expected developer behaviour
file_size: Current size in octets or records. Dev must: Your local application must keep this in sync with reality (after writes, appends, truncates). The override makes it writable only under certain conditions (e.g. not whenread_only, or for growable files).file_access_method(stream or record): How the file is accessed. Dev must: Set at creation based on your storage. The services use it to decide how to read.modification_date: Last change time. Dev must: Update (viaupdate_property/3) whenever your layer modifies the underlying file (write, append, etc.).read_only,archive: Flags. Dev must: Your storage enforcesread_only(refuse writes).archiveis informational (for backup, etc.).
The object is metadata only; the real work (byte streaming) is in the service handlers + your FS abstraction. See "You own the storage", "The services do the heavy lifting" and "Writing the metadata".
The File object is purely a handle + metadata for something that the
AtomicReadFile / AtomicWriteFile services will actually transfer.
You own the storage: The object only publishes file_size, file_access_method
(stream vs. record), modification_date, archive, read_only, etc. Your
file system abstraction, respectively your application code,
(flash, SD card, virtual config database, firmware image store, …) must keep
those fields current.
The services do the heavy lifting: When a client does AtomicReadFile or
AtomicWriteFile using this object's ObjectIdentifier, your application code
looks up the File object, checks file_access_method, read_only, current
size, etc., and then streams the actual bytes to/from your storage layer.
The object itself does not contain the data.
Typical uses:
- Firmware images (written by the vendor tool, read by the device on ReinitializeDevice or by a loader).
- Configuration databases (the device writes them, a workstation can read them for backup or edit them and write them back).
- Trend export files (the device periodically appends records to a file that a client can then read with the file services or via a Trend Log).
Access method: stream vs. record affects how the file services interpret
the offsets and how much data is transferred per PDU. Your storage layer
must implement both (or at least the one advertised by the File object).
The generated tables tell you exactly which fields are readonly, which have defaults, and which annotations affect encoding.
File objects are the bridge between the "normal object world" (Read/Write Property) and the bulk data transfer world (the file services). A developer implementing them needs to keep the metadata on the object in sync with the real storage while letting the service layer do the actual octet/record movement.
Examples
Creating a File object:
iex> {:ok, f} = BACnet.Protocol.ObjectTypes.File.create(1500, "ConfigFile", %{}); f.object_name
"ConfigFile"See Also
The following part has been automatically generated.
Click to expand
This module defines a BACnet object of the type `file`. The following properties are defined: | Property | Revision | Required | Readonly | Protected | Intrinsic | |----------|----------|----------|----------|-----------|-----------| | archive | | X | | | | | description | | | | | | | file_access_method | | X | X | | | | file_size | | X | X | | | | file_type | | X | | | | | modification_date | | X | | | | | object_instance | | X | X | | | | object_name | | X | X | | | | profile_location | 19 | | | | | | profile_name | | | | | | | read_only | | X | | | | | record_count | | | | | | | tags | 19 | | | | | The following properties have additional semantics: | Property | Has Default | Has Init | Implicit Relationships | Validators | Annotations | |----------|-------------|----------|------------------------|------------|-------------| | file_access_method | X | | | | | | file_size | X | | | | | | file_type | X | | | | | | modification_date | X | | | | | | profile_location | | | | Fun | `revision: 19` | | record_count | | | | Fun | | | tags | | | | | `revision: 19` | The following table shows the default values and/or init functions: | Property | Default Value | Init Function | |----------|---------------|---------------| | file_access_method | `:stream_access` | | | file_size | `0` | | | file_type | `"regular"` | | | modification_date | `%BACnet.Protocol.BACnetDateTime{...}` | |Summary
Types
Common object options for creation - all are optional.
Options accepted when creating or configuring a File object.
Available property names for this object.
The structure for property errors.
Represents a File object. All keys should be treated as read-only,
all updates should go only through update_property/3.
Functions
Adds an optional property to an object. Remote objects can not be mutated using this operation.
Creates a new object struct with the defined properties. Optional properties are not
created when not given, only required, given and dependency properties are created.
Properties with a value of nil are ignored.
Auto generated function to get the names of all properties this object supports.
Auto generated function to get the annotations for the given property name.
Auto generated function to get the list of annotations for each property.
Auto generated function to get the names of properties used for COV reporting.
Auto generated function to get the names of intrinsic properties.
Get the BACnet object identifier.
Auto generated function to get the names of optional properties.
Get the list of properties the object has.
Auto generated function to get a map of property name to type.
Get a property's value from an object.
Auto generated function to get the names of protected properties.
Auto generated function to get the names of readonly properties.
Auto generated function to get the names of required properties.
Checks if the given object has the given property.
Checks if the given property is writable.
Removes an optional property from an object. This function is idempotent. Remote objects can not be mutated using this operation.
Auto generated function to check whether the object type supports intrinsic reporting.
Updates a property of an object.
Types
@type common_object_opts() :: {:allow_numeric_constants, boolean()} | {:allow_unknown_properties, boolean()} | {:ignore_unknown_properties, boolean()} | {:revision, BACnet.Protocol.Constants.protocol_revision()} | {:skip_property_validation_remote_object, boolean() | :value}
Common object options for creation - all are optional.
allow_numeric_constants- Constants are atoms and thus unknown constants or vendor extensions are integers and thus are rejected. Enabling this option will allow integers (non_neg_integer()) for properties with aConstants.type()spec.allow_unknown_properties- Properties that are unknown to the object implementation are usually rejected. With this option, unknown properties (numeric identifiers usually means we dont know them) are accepted and put into a separate map. This does mean we can not validate or write them. Types of the values can be anything at this point. While you can read unknown properties with atom or integer as property identifier, you can only remove numeric unknown property identifiers from an object. Property identifiers of typeatomare only accepted, if it is a remote object (object implementation is only enforced if it is a local object). Numeric property identifiers are accepted regardless of remote object or not. For remote objects, this means you have to write "raw values" (usuallyEncodingstructs).ignore_unknown_properties- Properties that are unknown to the object implementation are usually rejected. With this option, unknown properties get ignored, as if they were not specified.revision- The BACnet protocol revision to check required properties against. Optional properties are regardless of revision available. SeeBACnet.Protocol.Constants.protocol_revision/0for the available revisions.skip_property_validation_remote_object- Skips property validation for remote objects. Sometimes it is possible that the value is invalid as per BACnet specification (i.e. value 0 for a multistate object), but you still want those to be represented. Valuetrueneither type nor value are validated. Value:valuemeans the type is still validated and only the value validator is not run (if present). The property'svalidator_funwill also be skipped.
@type object_opts() :: common_object_opts()
Options accepted when creating or configuring a File object.
@type property_name() ::
:archive
| :description
| :file_access_method
| :file_size
| :file_type
| :modification_date
| :object_instance
| :object_name
| :profile_location
| :profile_name
| :read_only
| :record_count
| :tags
Available property names for this object.
@type property_update_error() :: {:error, {error :: atom(), property :: BACnet.Protocol.Constants.property_identifier()}}
The structure for property errors.
@type t() :: %BACnet.Protocol.ObjectTypes.File{ _metadata: internal_metadata(), _unknown_properties: %{ optional(atom() | non_neg_integer()) => term() | BACnet.Protocol.ApplicationTags.Encoding.t() | [BACnet.Protocol.ApplicationTags.Encoding.t()] }, archive: boolean(), description: String.t() | nil, file_access_method: BACnet.Protocol.Constants.file_access_method() | (reserved_or_vendor_extension :: non_neg_integer()), file_size: non_neg_integer(), file_type: String.t(), modification_date: BACnet.Protocol.BACnetDateTime.t(), object_instance: non_neg_integer(), object_name: String.t(), profile_location: String.t() | nil, profile_name: String.t() | nil, read_only: boolean(), record_count: non_neg_integer() | nil, tags: BACnet.Protocol.BACnetArray.t(BACnet.Protocol.NameValue.t()) | nil }
Represents a File object. All keys should be treated as read-only,
all updates should go only through update_property/3.
Functions
@spec add_property(t(), BACnet.Protocol.Constants.property_identifier(), term()) :: {:ok, t()} | property_update_error()
Adds an optional property to an object. Remote objects can not be mutated using this operation.
Please note that properties of services can not be dynamically added and instead
the object must be newly created using create/4.
@spec create( non_neg_integer(), String.t(), %{optional(property_name() | atom() | non_neg_integer()) => term()}, [object_opts() | internal_metadata()] ) :: {:ok, t()} | property_update_error()
Creates a new object struct with the defined properties. Optional properties are not
created when not given, only required, given and dependency properties are created.
Properties with a value of nil are ignored.
Only properties that are required for specific services (i.e. Intrinsic Reporting) are automatically created.
@spec get_all_properties() :: [BACnet.Protocol.Constants.property_identifier()]
Auto generated function to get the names of all properties this object supports.
@spec get_annotation(property_name()) :: [term()]
Auto generated function to get the annotations for the given property name.
@spec get_annotations() :: [{name :: property_name(), values :: [term()]}]
Auto generated function to get the list of annotations for each property.
@spec get_cov_properties() :: [BACnet.Protocol.Constants.property_identifier()]
Auto generated function to get the names of properties used for COV reporting.
@spec get_intrinsic_properties() :: [BACnet.Protocol.Constants.property_identifier()]
Auto generated function to get the names of intrinsic properties.
@spec get_object_identifier(t()) :: BACnet.Protocol.ObjectIdentifier.t()
Get the BACnet object identifier.
@spec get_optional_properties() :: [BACnet.Protocol.Constants.property_identifier()]
Auto generated function to get the names of optional properties.
@spec get_properties(t()) :: [BACnet.Protocol.Constants.property_identifier()]
Get the list of properties the object has.
@spec get_properties_type_map() :: map()
Auto generated function to get a map of property name to type.
@spec get_property( t(), BACnet.Protocol.Constants.property_identifier() | non_neg_integer() ) :: {:ok, term()} | property_update_error()
Get a property's value from an object.
@spec get_protected_properties() :: [BACnet.Protocol.Constants.property_identifier()]
Auto generated function to get the names of protected properties.
Protected is an annotation and the object modules prevent writing to this property directly in code. The protected properties are either written on creation or updated automatically depending on other properties being written to. Some properties are only written once at creation and never updated.
@spec get_readonly_properties() :: [BACnet.Protocol.Constants.property_identifier()]
Auto generated function to get the names of readonly properties.
Readonly is only an annotation that the property should be write protected
on the BACnet side, there is no actual write protection in the object.
This is a hint to the device server. If you need actual write protection, see protected.
@spec get_required_properties() :: [BACnet.Protocol.Constants.property_identifier()]
Auto generated function to get the names of required properties.
@spec has_property?(t(), BACnet.Protocol.Constants.property_identifier()) :: boolean()
Checks if the given object has the given property.
See BACnet.Protocol.ObjectsUtility.has_property?/2 for implementation details.
@spec property_writable?(t(), BACnet.Protocol.Constants.property_identifier()) :: boolean()
Checks if the given property is writable.
Check BACnet.Protocol.ObjectsUtility.property_writable?/2 for a basic run-down.
@spec remove_property( t(), BACnet.Protocol.Constants.property_identifier() | non_neg_integer() ) :: {:ok, t()} | property_update_error()
Removes an optional property from an object. This function is idempotent. Remote objects can not be mutated using this operation.
Please note that properties of services can not be dynamically removed and instead
the object must be newly created using create/4. Required properties can not be removed.
@spec supports_intrinsic() :: boolean()
Auto generated function to check whether the object type supports intrinsic reporting.
@spec update_property(t(), BACnet.Protocol.Constants.property_identifier(), term()) :: {:ok, t()} | property_update_error()
Updates a property of an object.