@@ -616,6 +616,9 @@ public class TestPhysicalAdapter extends PhysicalAdapter {
616616}
617617```
618618
619+ Both Physical Adapters and Digital Adapters can be defined natively with a custom configuration provided by the developer
620+ as illustrated in the dedicated Section: [ Configurable Physical & Digital Adapters] ( #configurable-physical-and-digital-adapters ) .
621+
619622### Shadowing Function
620623
621624After the definition of the Physical Adapter it is time to start implementing the core of our DT through the definition of
@@ -1353,6 +1356,9 @@ protected void onDigitalTwinStateEventNotificationReceived(DigitalTwinStateEvent
13531356}
13541357```
13551358
1359+ Both Physical Adapters and Digital Adapters can be defined natively with a custom configuration provided by the developer
1360+ as illustrated in the dedicated Section: [Configurable Physical & Digital Adapters](#configurable-physical-and-digital-adapters).
1361+
13561362## Digital Twin Process
13571363
13581364Now that we have created the main fundamental element of a DT (Physical Adapter, Shadowing Function and Digital Adapter) we can create Class file with a main to create the WLDT Engine
@@ -1691,3 +1697,286 @@ protected void onStateChangeRelationshipInstanceDeleted(DigitalTwinStateRelation
16911697 System . out. println(" [TestDigitalAdapter] -> onStateChangeRelationshipInstanceDeleted(): " + digitalTwinStateRelationshipInstance);
16921698}
16931699```
1700+
1701+ ## Configurable Physical and Digital Adapters
1702+
1703+ The WLDT library provides a native method to define Configurable Physical ad Digital Adapters specifying a
1704+ custom configuration class passed as parameter in the constructor.
1705+
1706+ Starting with the Physical Adapter created in the previous example ```TestPhysicalAdapter ``` instead of extending the
1707+ base class ```PhysicalAdapter``` we can extend now ```ConfigurablePhysicalAdapter<C>``` where ```C``` is the name of the
1708+ that we would like to use as configuration.
1709+
1710+ In our example we can create a simple configuration class called ```TestPhysicalAdapterConfiguration``` where we move
1711+ the constant variable used to implement the behaviour of our demo physical adapter. The resulting class will be the
1712+ following:
1713+
1714+ ```java
1715+ public class TestPhysicalAdapterConfiguration {
1716+
1717+ private final static int MESSAGE_UPDATE_TIME = 1000 ;
1718+ private final static int MESSAGE_UPDATE_NUMBER = 10 ;
1719+ private final static double TEMPERATURE_MIN_VALUE = 20 ;
1720+ private final static double TEMPERATURE_MAX_VALUE = 30 ;
1721+
1722+ private int messageUpdateTime = MESSAGE_UPDATE_TIME ;
1723+
1724+ private int messageUpdateNumber = MESSAGE_UPDATE_NUMBER ;
1725+
1726+ private double temperatureMinValue = TEMPERATURE_MIN_VALUE ;
1727+
1728+ private double temperatureMaxValue = TEMPERATURE_MAX_VALUE ;
1729+
1730+ public TestPhysicalAdapterConfiguration () {
1731+ }
1732+
1733+ public TestPhysicalAdapterConfiguration (int messageUpdateTime , int messageUpdateNumber , double temperatureMinValue , double temperatureMaxValue ) {
1734+ this . messageUpdateTime = messageUpdateTime;
1735+ this . messageUpdateNumber = messageUpdateNumber;
1736+ this . temperatureMinValue = temperatureMinValue;
1737+ this . temperatureMaxValue = temperatureMaxValue;
1738+ }
1739+
1740+ public int getMessageUpdateTime () {
1741+ return messageUpdateTime;
1742+ }
1743+
1744+ public void setMessageUpdateTime (int messageUpdateTime ) {
1745+ this . messageUpdateTime = messageUpdateTime;
1746+ }
1747+
1748+ public int getMessageUpdateNumber () {
1749+ return messageUpdateNumber;
1750+ }
1751+
1752+ public void setMessageUpdateNumber (int messageUpdateNumber ) {
1753+ this . messageUpdateNumber = messageUpdateNumber;
1754+ }
1755+
1756+ public double getTemperatureMinValue () {
1757+ return temperatureMinValue;
1758+ }
1759+
1760+ public void setTemperatureMinValue (double temperatureMinValue ) {
1761+ this . temperatureMinValue = temperatureMinValue;
1762+ }
1763+
1764+ public double getTemperatureMaxValue () {
1765+ return temperatureMaxValue;
1766+ }
1767+
1768+ public void setTemperatureMaxValue (double temperatureMaxValue ) {
1769+ this . temperatureMaxValue = temperatureMaxValue;
1770+ }
1771+ }
1772+ ```
1773+
1774+ Now we can create or update our Physical Adapter extending ```ConfigurablePhysicalAdapter<DemoPhysicalAdapterConfiguration > ```
1775+ as illustrated in the following snippet:
1776+
1777+ ```java
1778+ public class TestPhysicalAdapter extends ConfigurablePhysicalAdapter<DemoPhysicalAdapterConfiguration > {
1779+ [... ]
1780+ }
1781+ ```
1782+
1783+ Extending this class also the constructor should be updated getting as a parameter the expected configuration instance.
1784+ Our constructor will be the following:
1785+
1786+ ```java
1787+ public TestConfPhysicalAdapter(String id, DemoPhysicalAdapterConfiguration configuration) {
1788+ super (id , configuration );
1789+ }
1790+ ```
1791+
1792+ After that change since we removed and moved the used constant values into the new Configuration class we have also to
1793+ update the ```deviceEmulation()``` method having access to the configuration through the method ```getConfiguration()``` or ```this.getConfiguration()```
1794+ directly on the adapter.
1795+
1796+ ```java
1797+ private Runnable deviceEmulation(){
1798+ return () -> {
1799+ try {
1800+
1801+
1802+ System . out. println(" [DemoPhysicalAdapter] -> Sleeping before Starting Physical Device Emulation ..." );
1803+
1804+ // Sleep 5 seconds to emulate device startup
1805+ Thread . sleep(10000 );
1806+
1807+ System . out. println(" [DemoPhysicalAdapter] -> Starting Physical Device Emulation ..." );
1808+
1809+ // Create a new random object to emulate temperature variations
1810+ Random r = new Random ();
1811+
1812+ // Publish an initial Event for a normal condition
1813+ publishPhysicalAssetEventWldtEvent(new PhysicalAssetEventWldtEvent<> (OVERHEATING_EVENT_KEY , " normal" ));
1814+
1815+ // Emulate the generation on 'n' temperature measurements
1816+ for (int i = 0 ; i < getConfiguration(). getMessageUpdateNumber(); i++ ){
1817+
1818+ // Sleep to emulate sensor measurement
1819+ Thread . sleep(getConfiguration(). getMessageUpdateTime());
1820+
1821+ // Update the
1822+ double randomTemperature = getConfiguration(). getTemperatureMinValue() + (getConfiguration(). getTemperatureMaxValue() - getConfiguration(). getTemperatureMinValue()) * r. nextDouble();
1823+
1824+ // Create a new event to notify the variation of a Physical Property
1825+ PhysicalAssetPropertyWldtEvent<Double > newPhysicalPropertyEvent = new PhysicalAssetPropertyWldtEvent<> (TEMPERATURE_PROPERTY_KEY , randomTemperature);
1826+
1827+ // Publish the WLDTEvent associated to the Physical Property Variation
1828+ publishPhysicalAssetPropertyWldtEvent(newPhysicalPropertyEvent);
1829+ }
1830+
1831+ // Publish a demo Physical Event associated to a 'critical' overheating condition
1832+ publishPhysicalAssetEventWldtEvent(new PhysicalAssetEventWldtEvent<> (OVERHEATING_EVENT_KEY , " critical" ));
1833+
1834+ } catch (EventBusException | InterruptedException e) {
1835+ e. printStackTrace();
1836+ }
1837+ };
1838+ }
1839+ ```
1840+
1841+ A similar approach can be adopted also for the Digital Adapter with the small difference that the base class
1842+ ```DigitalAdapter ``` already allow the possibility to specify a configuration. For this reason in the previous example
1843+ we extended ```DigitalAdapter<Void > ``` avoiding to specifying a configuration.
1844+
1845+ In this updated version we can create a new ```TestDigitalAdapterConfiguration``` class containing the parameter association
1846+ to the emulation of the action and then update our adapter to support the new configuration. Our new configuration class will be:
1847+
1848+ ```java
1849+ public class TestDigitalAdapterConfiguration {
1850+
1851+ private static final int SLEEP_TIME_MS = 1000 ;
1852+
1853+ private static final int EMULATED_ACTION_COUNT = 5 ;
1854+
1855+ private final static double TEMPERATURE_MIN_VALUE = 20 ;
1856+
1857+ private final static double TEMPERATURE_MAX_VALUE = 30 ;
1858+
1859+ private int sleepTimeMs = SLEEP_TIME_MS ;
1860+
1861+ private int emulatedActionCount = EMULATED_ACTION_COUNT ;
1862+
1863+ private double temperatureMinValue = TEMPERATURE_MIN_VALUE ;
1864+
1865+ private double temperatureMaxValue = TEMPERATURE_MAX_VALUE ;
1866+
1867+ public TestDigitalAdapterConfiguration () {
1868+ }
1869+
1870+ public TestDigitalAdapterConfiguration (int sleepTimeMs , int emulatedActionCount , double temperatureMinValue , double temperatureMaxValue ) {
1871+ this . sleepTimeMs = sleepTimeMs;
1872+ this . emulatedActionCount = emulatedActionCount;
1873+ this . temperatureMinValue = temperatureMinValue;
1874+ this . temperatureMaxValue = temperatureMaxValue;
1875+ }
1876+
1877+ public int getSleepTimeMs () {
1878+ return sleepTimeMs;
1879+ }
1880+
1881+ public void setSleepTimeMs (int sleepTimeMs ) {
1882+ this . sleepTimeMs = sleepTimeMs;
1883+ }
1884+
1885+ public int getEmulatedActionCount () {
1886+ return emulatedActionCount;
1887+ }
1888+
1889+ public void setEmulatedActionCount (int emulatedActionCount ) {
1890+ this . emulatedActionCount = emulatedActionCount;
1891+ }
1892+
1893+ public double getTemperatureMinValue () {
1894+ return temperatureMinValue;
1895+ }
1896+
1897+ public void setTemperatureMinValue (double temperatureMinValue ) {
1898+ this . temperatureMinValue = temperatureMinValue;
1899+ }
1900+
1901+ public double getTemperatureMaxValue () {
1902+ return temperatureMaxValue;
1903+ }
1904+
1905+ public void setTemperatureMaxValue (double temperatureMaxValue ) {
1906+ this . temperatureMaxValue = temperatureMaxValue;
1907+ }
1908+ }
1909+ ```
1910+
1911+ After that we can update the declaration of our Digital Adapter and modify its constructor to accept the configuration.
1912+ The resulting class will be:
1913+
1914+ ```java
1915+ public class TestDigitalAdapter extends DigitalAdapter<TestDigitalAdapterConfiguration > {
1916+
1917+ public TestDigitalAdapter (String id , TestDigitalAdapterConfiguration configuration ) {
1918+ super (id, configuration);
1919+ }
1920+
1921+ [... ]
1922+ }
1923+ ```
1924+
1925+ Of course the possibility to have this configuration will allow us to improve the ```emulateIncomingDigitalAction``` method
1926+ in the following way having access to the configuration through the method ```getConfiguration()``` or ```this . getConfiguration()```
1927+ directly on the adapter:
1928+
1929+ ```java
1930+ private Runnable emulateIncomingDigitalAction(){
1931+ return () - > {
1932+ try {
1933+
1934+ System . out. println(" [DemoDigitalAdapter] -> Sleeping before Emulating Incoming Digital Action ..." );
1935+ Thread . sleep(5000 );
1936+ Random random = new Random ();
1937+
1938+ // Emulate the generation on 'n' temperature measurements
1939+ for (int i = 0 ; i < getConfiguration(). getEmulatedActionCount(); i++ ){
1940+
1941+ // Sleep to emulate sensor measurement
1942+ Thread . sleep(getConfiguration(). getSleepTimeMs());
1943+
1944+ double randomTemperature = getConfiguration(). getTemperatureMinValue() + (getConfiguration(). getTemperatureMaxValue() - getConfiguration(). getTemperatureMinValue()) * random. nextDouble();
1945+ publishDigitalActionWldtEvent(" set-temperature-action-key" , randomTemperature);
1946+
1947+ }
1948+
1949+ } catch (Exception e) {
1950+ e. printStackTrace();
1951+ }
1952+ };
1953+ }
1954+ ```
1955+
1956+ When we have updated both adapters making them configurable we can update our ```main``` function in the process
1957+ that we have previouly device using the updated adapters and passing the configurations:
1958+
1959+ ````java
1960+ public class TestDigitalTwin {
1961+
1962+ public static void main (String [] args ) {
1963+ try {
1964+
1965+ WldtEngine digitalTwinEngine = new WldtEngine (new DemoShadowingFunction (" test-shadowing-function" ), " test-digital-twin" );
1966+
1967+ // Default Physical and Digital Adapter
1968+ // digitalTwinEngine.addPhysicalAdapter(new TestPhysicalAdapter("test-physical-adapter"));
1969+ // digitalTwinEngine.addDigitalAdapter(new TestDigitalAdapter("test-digital-adapter"));
1970+
1971+ // Physical and Digital Adapters with Configuration
1972+ digitalTwinEngine. addPhysicalAdapter(new TestConfPhysicalAdapter (" test-physical-adapter" , new TestPhysicalAdapterConfiguration ()));
1973+ digitalTwinEngine. addDigitalAdapter(new TestConfDigitalAdapter (" test-digital-adapter" , new TestDigitalAdapterConfiguration ()));
1974+
1975+ digitalTwinEngine. startLifeCycle();
1976+
1977+ }catch (Exception e){
1978+ e. printStackTrace();
1979+ }
1980+ }
1981+ }
1982+ ````
0 commit comments