diff --git a/doc/source/README.rst b/doc/source/README.rst index ad001d0d..e55fb201 100644 --- a/doc/source/README.rst +++ b/doc/source/README.rst @@ -1,41 +1,50 @@ BAC0 |build-status| |coverage| |docs| ===================================== -BAC0 is a Python 3 (3.4 and over) scripting application that uses BACpypes_ to process BACnet messages on a IP network. -This library brings out simple commands to browse a BACnet network, read properties from BACnet devices or write to them. +BAC0 is a Python 3 (3.4 and later) scripting application that uses BACpypes_ to process BACnet messages on a IP network. +This library exposes simple functions to browse the BACnet network, and read & write properties from the BACnet devices. -Python is a simple language to learn and a very powerful tool for data processing. Coupled to BACnet, it becomes a great -tool to test devices an interact with controllers. +Python is a simple language to learn and a very powerful tool for data processing. Coupled with BACnet, +it becomes a **great tool for testing BACnet** and interacting with BACnet controllers. -BAC0 takes its name from the default IP port used by BACnet/IP communication which is port 47808. In hexadecimal, it's written 0xBAC0. +BAC0 takes its name from the default IP port assigned to BACnet/IP communications - port (47808 decimal, 0xBAC0 +hexadecimal). Test driven development (TDD) for DDC controls ============================================== -BAC0 is made for building automation system (BAS) programmers. Controllers used in this field are commonly called DDC Controllers (Direct Digital Control). +BAC0 is intended for assisting BAS (building automation system) programmers, with configuring, testing, and +commissioning of BAS Controllers - often called DDC (Direct Digital Control) Controllers. -Typical controllers can be programmed in different ways, depending on the manufacturer selling them (block programming, basic "kinda" scripts, C code, etc...). -BAC0, is a unified way, using Python language and BACnet/IP communication, to interact with those controllers once their sequence is built. +Typically BAS controllers are programmed using vendor specific tools, and vendor specific programming languages +to define how they will operate. The resulting programs are the controller's **sequence of operations**. +Different vendors, use different methods to define these sequences - including 'block programming', +'graphical programming', and 'text/procedural programming'. -BAC0 allows users to simply test an application even if sensors are not connected to the controller. Using the out_of_service -property, it's easy to write a value to the input so the controller will think an input is conencted. +BAC0 provides a generalized (vendor-independent) means to programmatically interact with the BAS controllers, +via Python and the BACnet/IP communication protocol. BAC0 allows users to test a controller even if no sensors +or outputs are connected to the controller. Thanks to the BACnet **out_of_service** property, it is easy to write +a value to the input pin(s) so the controller believes a sensor is connected, and its **operating sequence** will +respond accordingly. Likewise, it is possible to write a value to an output pin(s) to operate any connected +equipment (often called a **manual command** or to **override an output**). In fact, BAC0 exposes a great many of a +controller's BACnet Objects and Object Properties, enabling automated interactions using Python; as a simple +scripting language, a powerful testing & commissioning tool, or a general application development environment. -It's also possible to do "manual commands" on output (often called overrides). In fact, every variable is exposed and seen by BAC0 and -it's possible to interact with them using a simple scripting language or a complete unit test suite (like Pytest). +Using BAC0 as test tool, makes automated BAS testing quick, reliable, and repeatable. Compare this to +the BAS vendor provided tools, which only allow the controllers to be programmed, and where all the +testing must be done manually. Very slow. Very error-prone. Now you can write your tests and re-run them +as often as you need. -Without a program like BAC0, you can rely on your DDC programming tool... but it is often slow and -every test must be done manually. That means also that if you want to repeat the tests, the more complicated they are, the less chance you'll be able to do so. -Now you can write your test and run them as often as you want. We'll show you how it works. +Better commissioning thanks to automatic data logging +===================================================== +As you will discover, when you define a controller in BAC0, you automatically get **historical data logs** for +every variable in the controller. All I/O points are trended every 10 seconds (by default). Meaning +you can do data analysis of the controller's operation while you're doing your basic **sequence testing**. +This gives you a high-level overview of the controller's performance while highlighting trouble areas really fast. -Better start-up with data acquisition -===================================== -As you will discover, when you define a controller in BAC0, you will get access to historical data of -every variables in the controllers. Every points are trended every 10 seconds by default. Which means -that you can do data analysis on everything while you're doing your startup. It allows to see performances and -trouble really fast. - -This make BAC0 not only a good tool to test your sequence while your in the office. -But also a really good tool to assist your startup, test and balancing. Using Jupyter Notebook, you'll -even be able to create nice looking report right from your code. +BAC0 is not only a good tool for testing your **sequence of operations** while in-the-office. +It is also a really good tool to assist on-site. Use it to test controller startup, operation, and balancing +in-the-field. When combined with Jupyter Notebook, you are even able to create nice looking reports right from your +automation code. .. |build-status| image:: https://travis-ci.org/ChristianTremblay/BAC0.svg?branch=master diff --git a/doc/source/connect.rst b/doc/source/connect.rst index e7cc1513..72dd3641 100644 --- a/doc/source/connect.rst +++ b/doc/source/connect.rst @@ -27,39 +27,81 @@ To read a point, simply ask for it using bracket syntax:: mycontroller['point_name'] -Write to a point ----------------- -simple write + +Writing to Points +----------------- + +Simple write ************ -If point is a analogValue, binaryValue or a multistateValue BAC0 will write to the default -priority :: +If point is a value: + + * analogValue (AV) + * binaryValue (BV) + * multistateValue (MV) + +You can change its value with a simple assignment. BAC0 will write the value to the object's +**presentValue** at the default priority.:: + + mycontroller['point_name'] = 23 + +.. image:: images/AV_write.png + + +Write to an Output (Override) +***************************** +If the point is an output: + + * analogOutput (AO) + * binaryOutput (BO) + * multistateOutput (MO) + +You can change its value with a simple assignment. BAC0 will write the value to the object's +**presentValue** (a.k.a override it) at priority 8 (Manual Operator).:: + + mycontroller['outputName'] = 45 + +.. image:: images/AO_write.png + + +Write to an Input (simulate) +**************************** +If the point is an input: + + * analogInput (AI) + * binaryOutput (BO) + * multistateOutput (MO) + +You can change its value with a simple assigment, thus overriding any external value it is +reading and simulating a different sensor reading. The override occurs because +BAC0 sets the point's **out_of_service** (On) and then writes to the point's **presentValue**. + + mycontroller['inputName'] = + + mycontroller['Temperature'] = 23.5 # overiding actual reading of 18.8 C - mycontroller['point_name'] = 10 +.. image:: images/AI_override.png -Relinquish default -****************** -If you must write to relinquish default, it must be said explicitly :: - mycontroller['pointToChange'].default(10) +Releasing an Input simulation or Output override +************************************************* -This distinction is made because of the sensibility to multiple writes to those values. -Thoses are often written to EEPROM directly and have a ±250000 write cycle. +To return control of an Input or Output back to the controller, it needs to be released. +Releasing a point returns it automatic control. This is done with an assignment to 'auto'.:: -Override -********* -If the point is a output, BAC0 will override it (@priority 8):: + mycontroller['pointToRelease'] = 'auto' - mycontroller['outputName'] = 100 +.. image:: images/AI_auto.png +.. image:: images/AO_auto.png -simulate (out_of_service) -************************** -If the point is an input, BAC0 will set the out_of_service flag to On and write -to the present value (which will simulate it):: + +Setting a Relinquish_Default +**************************** +When a point (with a priority array) is released of all override commands, it takes on the value +of its **Relinquish_Default**. [BACnet clause 12.4.12] If you wish to set this default value, +you may with this command:: - mycontroller['inputName'] = 34 + mycontroller['pointToChange'].default() + mycontroller['Output'].default(75) -Releasing a simulation or an override -************************************** -Simply affect 'auto' to the point :: +.. image:: images/AO_set_default.png - mycontroller['pointToRelease'] = 'auto' \ No newline at end of file diff --git a/doc/source/histories.rst b/doc/source/histories.rst index 567252b1..6bb38404 100644 --- a/doc/source/histories.rst +++ b/doc/source/histories.rst @@ -1,34 +1,51 @@ Histories in BAC0 ==================== -As said, every points get saved in a pandas Series every 10 seconds by default. -This means that you can look for historical data from the moment you connect to a device. -Access a historyTable:: + +BAC0 uses the Python Data Analysis library **pandas** [http://pandas.pydata.org/] to +maintain histories of point values over time. All points are saved by BAC0 in a **pandas** +Series every 10 seconds (by default). This means you will automatically have historical data +from the moment you connect to a BACnet device. + +Access the contents of a point's history is very simple.:: - controller['nvoAI1'].history - -Result example :: - - controller['nvoAI1'].history - Out[8]: - 2015-09-20 21:41:37.093985 21.740000 - 2015-09-20 21:42:23.672387 21.790001 - 2015-09-20 21:42:34.358801 21.790001 - 2015-09-20 21:42:45.841596 21.790001 - 2015-09-20 21:42:56.308144 21.790001 - 2015-09-20 21:43:06.897034 21.790001 - 2015-09-20 21:43:17.593321 21.790001 - 2015-09-20 21:43:28.087180 21.790001 - 2015-09-20 21:43:38.597702 21.790001 - 2015-09-20 21:43:48.815317 21.790001 - 2015-09-20 21:44:00.353144 21.790001 - 2015-09-20 21:44:10.871324 21.790001 + controller['pointName'].history + +Example :: + + controller['Temperature'].history + 2017-03-30 12:50:46.514947 19.632507 + 2017-03-30 12:50:56.932325 19.632507 + 2017-03-30 12:51:07.336394 19.632507 + 2017-03-30 12:51:17.705131 19.632507 + 2017-03-30 12:51:28.111724 19.632507 + 2017-03-30 12:51:38.497451 19.632507 + 2017-03-30 12:51:48.874454 19.632507 + 2017-03-30 12:51:59.254916 19.632507 + 2017-03-30 12:52:09.757253 19.536366 + 2017-03-30 12:52:20.204171 19.536366 + 2017-03-30 12:52:30.593838 19.536366 + 2017-03-30 12:52:40.421532 19.536366 + dtype: float64 + + +.. note:: + **pandas** is an extensive data analysis tool, with a vast array of data manipulation operators. + Exploring these is beyond the scope of this documentation. Instead we refer you to this + cheat sheet [https://github.com/pandas-dev/pandas/blob/master/doc/cheatsheet/Pandas_Cheat_Sheet.pdf] and + the pandas website [http://pandas.pydata.org/]. + Resampling data --------------- -As those are pandas DataFrame or Series, you can resample data:: +One common task associated with point histories is preparing it for use with other tools. +This usually involves (as a first step) changing the frequency of the data samples - called +**resampling** in pandas terminology. - # This piece of code show what can of operation can be made using Pandas - +Since the point histories are standard pandas data structures (DataFrames, and Series), you can +manipulate the data with pandas operators, as follows.:: + + # code snipet showing use of pandas operations on a BAC0 point history. + # Resample (consider the mean over a period of 1 min) tempPieces = { '102_ZN-T' : local102['ZN-T'].history.resample('1min'), @@ -44,7 +61,7 @@ As those are pandas DataFrame or Series, you can resample data:: '110_ZN-T' : local110['ZN-T'].history.resample('1min'), '110_ZN-SP' : local110['ZN-SP'].history.resample('1min'), } - # Remove any NaN value + # Remove any NaN values temp_pieces = pd.DataFrame(tempPieces).fillna(method = 'ffill').fillna(method = 'bfill') # Create a new column in the DataFrame which is the error between setpoint and temperature @@ -57,4 +74,4 @@ As those are pandas DataFrame or Series, you can resample data:: # Create a new dataframe from results and show some statistics temp_erreurs = temp_pieces[['Erreur_102', 'Erreur_104', 'Erreur_105', 'Erreur_106', 'Erreur_109', 'Erreur_110']] - temp_erreurs.describe() \ No newline at end of file + temp_erreurs.describe() diff --git a/doc/source/images/AI_auto.png b/doc/source/images/AI_auto.png new file mode 100644 index 00000000..8395cb59 Binary files /dev/null and b/doc/source/images/AI_auto.png differ diff --git a/doc/source/images/AI_override.png b/doc/source/images/AI_override.png new file mode 100644 index 00000000..33bbd582 Binary files /dev/null and b/doc/source/images/AI_override.png differ diff --git a/doc/source/images/AO_auto.png b/doc/source/images/AO_auto.png new file mode 100644 index 00000000..72c4f46b Binary files /dev/null and b/doc/source/images/AO_auto.png differ diff --git a/doc/source/images/AO_set_default.png b/doc/source/images/AO_set_default.png new file mode 100644 index 00000000..9574a4c3 Binary files /dev/null and b/doc/source/images/AO_set_default.png differ diff --git a/doc/source/images/AO_write.png b/doc/source/images/AO_write.png new file mode 100644 index 00000000..ee2688e2 Binary files /dev/null and b/doc/source/images/AO_write.png differ diff --git a/doc/source/images/AV_write.png b/doc/source/images/AV_write.png new file mode 100644 index 00000000..296411d5 Binary files /dev/null and b/doc/source/images/AV_write.png differ diff --git a/doc/source/index.rst b/doc/source/index.rst index 29bc81d0..d611f660 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,8 +3,9 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to BACØ's documentation! -================================ +Welcome to BACØ - BACnet Test Tool +================================== + .. include:: README.rst @@ -22,9 +23,14 @@ Table of contents tests pytest -Modules documentation -===================== -.. include:: BAC0.rst + +Developer documentation +======================= +.. toctree:: + :maxdepth: 2 + + BAC0 + Index and search tool ====================== diff --git a/doc/source/pytest.rst b/doc/source/pytest.rst index 3ae69099..01a875ea 100644 --- a/doc/source/pytest.rst +++ b/doc/source/pytest.rst @@ -1,32 +1,24 @@ Using Pytest_ ============= -Pytest_ is a "a mature full-featured Python testing tool". -It allows the creation of test files that can be called by a command line script. -It's then possible to create different test, all in there own file start -the process and work on something else while tests are running. +Pytest_ [https://docs.pytest.org/en/latest/] is a "a mature full-featured Python testing tool". +It allows the creation of test files that can be called by a command line script, +and run automatically while you work on something else. -Here an example of a Pytest_ module that could be created. +For more details, please refer Pytest's documentation. -Please note that Pytest_ on its own is a very complete solution. For more documentation about -it, please refer to the documentation of the project. - -I'll simply describe minimal feature I present in the example. Some basic stuff before we begin -------------------------------- -Pytest is a very simple testing tool. The default unit test tool for python is called -unittest. Based on Java xUnit, it's more formal, uses a lot of different functions and classes... -It can easily become too much for the needs of testing DDC controllers. - -Pytest uses only simple `assert` command, inside functions defined in a module. +Pytest is a very simple testing tool. While, the default unit test tool for python is +**unittest** (which is more formal and has more features); unittest can easily become +too much for the needs of testing DDC controllers. -Pytest also allows the usage of "fixtures" which are little snippets of code that will be -used to prepare what's needed for the test, then finalize the process when it's over. In unittest, -thoses functions are called setUp and tearDown. +Pytest uses only simple the `assert` command, and locally defined functions. +It also allows the usage of "fixtures" which are little snippets of code that prepare things +prior to the test (setUp), then finalize things when the test is over (tearDown). -In the example module I'll show you, I'm using fixtures to create the BACnet connection at the beginning -of the test, making this connection valid for all the tests in the module, then closing the connection -after the tests have been done, just after having saved the controller so the histories be available. +The following example uses fixtures to establish the BACnet connection prior to the test, +and then saves the controller histories and closes the connection after the tests are done. Example +++++++ @@ -69,12 +61,12 @@ Code :: Success result .............. -If you named you file test_mytest.py, you can just run :: +If you name the file: test_mytest.py, you can just run :: py.test -v -s -Pytest_ will look for test files, find them and run them. Or you can define the -file you want to run :: +Pytest_ will look for the test files, find them and run them. Or you can define the +exact file you want to run :: py.test mytestfile.py -v -s @@ -117,7 +109,7 @@ Here's what it looks like :: Failure result .............. -Here's what it looks like when a test fails :: +Here's what a test failure looks like:: ============================= test session starts ============================= platform win32 -- Python 3.4.4, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- C:\User @@ -163,12 +155,12 @@ Here's what it looks like when a test fails :: pytest_example.py:30: AssertionError ===================== 1 failed, 1 passed in 30.71 seconds ===================== -I modified the test here to generate an failure if nvoAI2 is not greater than 1000. +Note: I modified the test to generate an failure - nvoAI2 cannot exceed 1000. Conclusion ---------- Using Pytest_ is a really good way to generate test files that can be reused and modified depending on different use cases. It's a good way to run multiple tests at once. -It will give you a concise report of every failure and tell you if tests succeeded. +It provides concise reports of every failure and tells you when your tests succeed. -.. _pytest : http://pytest.org/latest/ \ No newline at end of file +.. _pytest : http://pytest.org/latest/ diff --git a/doc/source/savedevice.rst b/doc/source/savedevice.rst index a7bb3775..e453acb4 100644 --- a/doc/source/savedevice.rst +++ b/doc/source/savedevice.rst @@ -1,39 +1,40 @@ Saving your data ================ -When doing some tests, it can be useful to go back in time and see what -happened before. BAC0 allow you to save your progress (historical data) to a file -so you'll be able to re-open your device later. +When doing tests, it can be useful to go back in time and see what +happened before. BAC0 allows you to save your progress (historical data) to a file +that you'll be able to re-open in your device later. Use :: controller.save() -and voila ! 2 new files will be created. One sqlite with all the histories, and -one bin file with all the details and properties of the device so it can be +and voila! Two files are created. One (an SQLite file) contains all the histories, and +one binary file containing all the details and properties of the device so the details can be rebuilt when needed. -By default, the 'object name' of the device will be used as the filename. But you can specify a name :: +By default, the 'object name' of the device is used as the filename. But you can specify a name :: controller.save(db='new_name') Offline mode ------------ -As already explained, a device in BAC0, if not connected (cannot be reached) will be -created as an offline device. If a database exist for this device, it will be -created and every points and histories will be available just like if you were +As already explained, a device in BAC0, if not connected (or cannot be reached) will be +created as an offline device. If a database exists for this device, it will automatically +loaded and all the points and histories will be available just as if if you were actually connected to the network. -You can also force a connection to the database if needed. Given a connected device use :: +You can also force a connection to use an existing database if needed. +Provide connect function with the desired database's name.:: controller.connect(db='db_name') -Please note that it's actually an experimental feature. +Please note: this feature is experimental. Saving Data to Excel -------------------- -Using the module called xlwings, it's possible to export all the data of the controller -to an Excel Workbook. +Thought the use of the Python module xlwings [https://www.xlwings.org/], it's possible to export all +the data of a controller into an Excel Workbook. Example :: - controller.to_excel() \ No newline at end of file + controller.to_excel() diff --git a/doc/source/tests.rst b/doc/source/tests.rst index 0d049bdf..d9cb7c06 100644 --- a/doc/source/tests.rst +++ b/doc/source/tests.rst @@ -1,30 +1,35 @@ Testing and simulating with BAC0 ================================ -Now you can build simple tests using assert syntax for example and make your DDC code stronger. + +BAC0 is a powerful BAS test tool. With it you can easily build tests scripts, and by +using its **assert** syntax, you can make your DDC code stronger. + Using Assert and other commands ------------------------------- -Let's say your sequence is really simple. Something like this : +Let's say your BAC controller **sequence of operation** is really simple. Something like this:: -System stopped --------------- -When system is stopped, fan must be off, dampers must be closed, heater cannot operate. + System stopped: + When system is stopped, fan must be off, + dampers must be closed, heater cannot operate. -System started --------------- -When system starts, fan command will be on. Dampers will open to minimum position. -If fan status turns on, heating sequence will starts. + System started: + When system starts, fan command will be on. + Dampers will open to minimum position. + If fan status turns on, heating sequence will start. And so on... How would I test that ? ----------------------- -* Controller is defined and its variable name is mycontroller -* fan command = SF-C -* Fan Status = SF-S -* Dampers command = MAD-O -* Heater = RH-O -* Occupancy command = OCC-SCHEDULE + +Assuming: + * Controller is defined and its variable name is mycontroller + * fan command = SF-C + * Fan Status = SF-S + * Dampers command = MAD-O + * Heater = RH-O + * Occupancy command = OCC-SCHEDULE System Stopped Test Code:: @@ -49,39 +54,44 @@ Sytstem Started Test Code:: And so on... -You are now able to define any test you want. You will probably use more precise conditions -instead of time.sleep() function (example read a value that tells actual mode is active) +You can define any test you want. As complex as you want. You will use more precise conditions +instead of a simple time.sleep() function - most likely you will read a point value that tells +you when the actual mode is active. + +You can then add tests for the various temperature ranges; and build functions to simulate discharge air +temperature depending on the heating or cooling stages... it's all up to you! -You can then test random temperature values, build functions that will simulate discharge air -temperature depending on heatign or cooling stages... it's up to you ! Using tasks to automate simulation ================================== + Polling ------- -Let's say you want to poll a point every 5 seconds to see later how the point reacted.:: +Let's say you want to poll a point every 5 seconds to see how the point reacted.:: mycontroller['point_name'].poll(delay=5) -Note that by default, polling is on for every points every 10 seconds. But you could have -define a controller without polling and do specific polling.:: +Note: by default, polling is enabled on all points at a 10 second frequency. But you could + define a controller without polling and do specific point polling.:: mycontroller = BAC0.device('2:5',5,bacnet,poll=0) mycontroller['point_name'].poll(delay=5) Match ----- -Let's say you want to automatically match the status of a point with the command.:: +Let's say you want to automatically match the status of a point with it's command to +find times when it is reacting to conditions other than what you expected.:: mycontroller['status'].match(mycontroller['command']) + Custom function --------------- -You could also define a complex function, and send it to the controller. +You could also define a complex function, and send that to the controller. This way, you'll be able to continue using all synchronous functions of Jupyter Notebook for example. (technically, a large function will block any inputs until it's finished) -PLEASE NOTE THAT THIS IS A WORK IN PROGRESS +.. note:: THIS IS A WORK IN PROGRESS Example :: @@ -95,6 +105,7 @@ Example :: controller.do(test_Vernier) -This function updates the variable named "Vernier Sim" each 30 seconds. By increment of 1 percent. -It will take a really long time to finish. Using the "do" method, you send the function to the controller -and it will be handled by a thread so you'll be able to continue working on the device. \ No newline at end of file +This function updates the variable named "Vernier Sim" each 30 seconds; incrementing by 1 percent. +This will take a really long time to finish. So instead, use the "do" method, and the function +will be run is a separate thread so you are free to continue working on the device, while the +function commands the controller's point. diff --git a/doc/source/trending.rst b/doc/source/trending.rst index 339eecd7..f1c86741 100644 --- a/doc/source/trending.rst +++ b/doc/source/trending.rst @@ -1,13 +1,16 @@ Trends ====== -Trending is a nice feature when you want to see what's going on. Until now, -it was possible to use matplotlib directly in Jupyter_ to show trends. +Trending is a nice feature when you want to see how a points value changed over time. +Until now, this was only possible using matplotlib directly in Jupyter_. +But I recently became aware of Bokeh_ [http://bokeh.pydata.org/en/latest/] which brings +a complete set of wonderful features for visualizing point histories (a.k.a. trends). +The best feature of all - the ability to see Live Trends of your data as it occurs. Matplotlib ---------- -Matplotlib_ is a well know library for plotting with python. As historical data are -pandas Series or DataFrame, it's possible to use Matplotlib with BAC0. -Show a chart using matplotlib:: +Matplotlib_ is a well known data plotting library for Python. As BAC0's historical point data +are pandas Series and DataFrames, it's possible to use Matplotlib with BAC0. +i.e. Showing a chart using matplotlib:: %matplotlib notebook # or matplotlib inline for a basic interface @@ -15,25 +18,30 @@ Show a chart using matplotlib:: |matplotlib| + Bokeh ----- -But I recently got aware of Bokeh_ which brings a complete new set of wonderful -features to see trends. Best of all, the ability to see Live Trends of your data. +Bokeh is a Python interactive visualization library targeting modern web browsers for presentation. +Its goal is to provide elegant, concise graphics, with high-performance interactivity over very large +or streaming datasets. Bokeh can help anyone who would like to quickly create interactive plots, dashboards, +and data applications. + +BAC0 trending features use Bokeh by default. -Default trending features of BAC0 now depends on Bokeh_ library Bokeh serve ----------- -To be able to use live trending features, a bokeh server needs to run locally on the machine. -When the application starts, a bokeh server will be started in a subprocess. -This server is available on localhost:5006, on your machine. +To use the live trending features, a bokeh server needs to be running locally on your computer. +When the BAC0 starts, it starts a bokeh server for you, running locally. This server is available +at localhost:5006, on your machine. -It's a shortcut so the user don't have to think about starting the server using:: +The server can be started manually, from the command line via:: bokeh serve -Note : Once started, the bokeh server won't be stopped by the BAC0. It will terminate when -Jupyter session will be closed. +Note : Once started, the bokeh server won't be stopped by the BAC0. It will terminate when your +Jupyter session is closed. + Add plots to Bokeh Document --------------------------- @@ -56,22 +64,23 @@ Empty at first, you need to send the data you want to the server using :: |bokeh_plots| -At startup, the script will give you the complete address to reach to get access -to the trends :: +At startup, BAC0 prints the complete URL address for your web browser to view trends :: Click here to open Live Trending Web Page http://localhost:5006/?bokeh-session-id=f9OdQd0LWSPXsnuNdCqVSoEa5xxwd32cZR0ioi9ACXzl + Bokeh Features -------------- -You'll get access to live stream of data and all the features of bokeh (zooming, span, etc.) -For more details, see http://www.bokehplots.com +Bokeh has an extensive set of features. Exploring them is beyond the scope of this documentation. +Instead you may discover them yourself at [http://www.bokehplots.com]. +A couple of its features are highlighted below. -Numerous options are provided by Bokeh plots like a hover tool. +Hover tool: |bokeh_hover| -And a lot of other options like pan, box zoom, mouse wheel zoom, save, etc... +And a lot of other options like pan, box zoom, mouse wheel zoom, save, etc...: |bokeh_tools|