Bahmni Connect Features
- Abishek Anand
- Angshuman Sarkar
- Rajeeb Rasak
Purpose and Benefits
The Offline feature of Bahmni (known as Bahmni Connect), allows Community Health Workers (CHW) to use Bahmni to register patients, view medical records, and enter brief treatment data in remote, internet-restrictive (no internet, intermittent connectivity etc) locations. Bahmni Connect is a single user, offline capable, limited functionality (compared to server version) application for users on the field.
If you need, multi user collaborative field level operational system, consider using Bahmni Server. For example, consider using a laptop running Bahmni, the laptop can be used to create a hotspot and then you can use other mobile devices to connect to the Bahmni instance.
Bahmni Connect on a broad level provides only 2 functionalities (and limited).
- Registration - view already registered patients, and do new registration
- Clinical - capture observation and view information (see below of supported information - like Diagnosis, Lab orders etc)
The information captured can be synced with the Bahmni Server and also information relevant to the logged in user's catchment can be downloaded to the device as well.
You can see a walkthrough video here. (although a bit outdated)
Bahmni Connect needs Bahmni Server to be working in sync and you will need to configure it to talk to the server.
Detailed below is a walkthrough of the various features available with Bahmni Connect.
Supported Features
1) Login Location
When a Community Health Worker (CHW) logs in to the application using the handheld device for the very first time they are authenticated against the server and granted access to the application. Along with this, their credentials are also stored in the handheld device for authentication when they are offline. When a CHW is offline and logged out of the application, he/she must be able to login to the application using the previously stored credentials that they used when they logged in when online. Only the last successful login is stored in the device.
CHWs are tied to a specific location from where they will operate. Transfers to other districts are rare and even if the CHW is transferred, the device used by the CHW stays in the same location. This eliminates the need for providing a choice of location to the CHW for every subsequent login.
The login location selected by the CHW will also have some catchment ids stored as an attribute of that location. These catchment ids and the login locations must be stored locally after the first successful login. For subsequent logins that happen when offline, the default login location will be fetched from the locally stored values and pre-populated on the login screen. The catchment ids pertaining to that login location must be fetched from the values stored locally and used to set the filter criteria for data from the server during sync.
For the first time, when the app is installed, all the available locations (pulled from OpenmMRS) are shown. Upon selection of login location and first successful login, set the selected login location as the default login location. This login location and the corresponding catchment ids (stored as login location attributes) are stored locally.
Development is currently in progress to make Bahmni Connect generic enough to support different kind of address hierarchies
The following java file must be defined to provide a location specific sync config for any given location
package org.bahmni.module.bahmniOfflineSync.filter; // before 0.85 package org.bahmni.module.bahmniOfflineSync.strategy; // after 0.85 import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class SampleLocationFilter implements FilterEvaluator { public SampleLocationFilter() { // initialize stuff if needed here } public String evaluateFilter(String uuid, String category) { String filter = ""; // decide the corresponding filter for Event Records return filter; } public Map<String,List<String>> getFilterForDevice(String provider, String addressUuid, String loginLocationUuid) { Map<String, List<String>> categoryFilterMap = new HashMap(); // populate the categoryFilterMap for the Login Locations return categoryFilterMap; } public List<String> getEventCategoriesList() { List<String> eventCategoryList = new ArrayList(); // populate the eventCategoryList for the categories to be synced return eventCategoryList; } }
Package name for the file is:
org.bahmni.module.bahmniOfflineSync.strategy.SampleLocationFilter (before 0.85)
org.bahmni.module.bahmniOfflineSync.strategy.SampleLocationFilter (after 0.85)
The package name mentioned above must be specified as a value in the OpenMRS global properties with the key bahmniOfflineSync.eventlog.filterEvaluator (before 0.85) and bahmniOfflineSync.strategy (after 0.85) for the system to pick it up.
This file needs to be written the the Bahmni Connect Sync (https://github.com/Bahmni/bahmni-offline-sync) and to be deployed as an omod in the OpenMRS modules. The following filter criteria will also be defined in this file.
2) Configuring Address Hierarchy
Bahmni Connect use the address configuration to sync data from Bahmni Connect to the online server. The address hierarchy may change or may be unique to a specific implementation. As an example, Bahmni address hierarchy for a national rollout may follow a top-down structure, where a set of lower levels are mapped to an upper level, while another set is mapped to another upper level, which systemically goes up - based on which Bahmni Connect syncs with the server. Another use case could be where there are multiple sub-centers and the implementation follows a flat hierarchy.
Taking these into consideration, a filter criteria can be set based on which Bahmni Connect will sync with server, so that Bahmni Connect can work across multiple address configurations.
The filter criteria definition may not be exhaustive to cover any future use-cases that could possibly come up. In such a case, specific implementation-based filter criteria has to be defined.
3) Configuration to Set Bahmni Online / Bahmni Connect Apps
Certain apps such as national registry need to be displayed on the offline device only when it is connected online. Similarly certain features such as error logs need not be displayed when the device is offline. The below changes have to be done to extension.json located at bahmni_config/openmrs/apps/home/
Example 1) "exclusiveOnlineModule": true
Here exclusiveOnlineModule is set to true. This means the app should only be shown when the offline device is connected to the internet.
"bahmni_nationalregistry_search": { "extensionPointId": "org.bahmni.home.dashboard", "url": "../../openmrs/shrclient/mciPatient.page", "order": 7, "translationKey": "National Registry", "requiredPrivilege": "National Registry", "type": "link", "id": "bahmni.nationalregistry.search", "icon": "fa-user", "exclusiveOnlineModule": true }
Example 2) "exclusiveOfflineModule": true
Here exclusiveOfflineModule is set to true. This means the app should be only shown when the offline device is not connected to internet.
"bahmni_nationalregistry_search": { "extensionPointId": "org.bahmni.home.dashboard", "url": "../../openmrs/shrclient/mciPatient.page", "order": 7, "translationKey": "National Registry", "requiredPrivilege": "National Registry", "type": "link", "id": "bahmni.nationalregistry.search", "icon": "fa-user", "exclusiveOfflineModule": true }
If Neither of exclusiveOnlineModule or exclusiveOfflineModule is configured, then the app(s) will always be shown in the Bahmni Connect.
4) Configuring Support for Multiple Catchment Areas
An address hierarchy entry may have more than one login location and each login location may cater only to a group of child address entries. In this case OpenMRS Admin UI does not allow configuration of multiple catchment area under a single login location. In this case we can use the location attribute "catchmentFilters". The user generated ids (address_hierarchy_entry.user_generated_id) of the 'areas' can be configured as a value for this attribute as comma separated values.
The location-based filter evaluator will get the data based on the filters configured here. If there is no configured values, then data for all the areas under the address for the login location is fetched.
Steps to follow:
- In OpenMRS go to "Manage Location Attribute Types"
- Create a location attribute type called "catchmentFilters" and save the location attribute type.
- Go to "Manage Locations" and open your login location
- Fill the "catchmentFilters" attribute with the names of preferred wards as comma separated value and save the location
Please note that if the penultimate location drop-down is selected, then the configured catchments will not be considered. For example, in the above picture, if Rural Ward is selected (such as Rural Ward = Ward No-01), then the catchmentFilters will not work; instead only Ward No-01 will be considered.
5) Display Controls Supported by Bahmni
The display controls currently supported by Bahmni Connect client are:
- Diagnosis (view only)
- Observations
- Lab orders (view only)
- Visit display (view only)
- Treatment/Drug Info ((view only)
These display controls are updated after the Bahmni Connect client syncs with the server.
Registration
Bahmni Connect supports the following major features of the Registration module
- Configurable Patient Search based on name, id, address, or custom attributes
- Capture of patient details (identity, name, age, gender, custom attributes).
- Editing of existing patient details
Features not yet supported
- Capture relationships between patients and other patients/doctors
- Death Information
- Start Visit from registration page
- Registration Second Page
- Showing existing patient images
- Take patient images during patient registration
- Print registration card
- Autocomplete options for patient name, family name, lastname
- The login location dropdown on the header of home is not shown in offline, as login location cannot be changed
- Capturing orders and medications on offline client
The only difference in the functionality of the registration module offline relates to ID generation. For patients created offline an identifier will not be generated until the patient has been synced back to the bahmni server. Until then on the registration page the identifier row will not be visible. On the patient search page the identifier column of the patient in the search results list will show a value of 'Not Assigned'.
** Diagnosis display control displays diagnosis for patient when it syncs when offline client syncs with Bahmni online, where the diagnosis is captured
Tech Solution
All patients synced to the offline device are stored in the offline database as documents. In this case the document is the patient JSON which has all the information to render the patient details page of the patient. To enable search all pertinent information is extracted from the JSON and stored in the offline database tables as columns to speed up searching.
All offline database manipulations require 2 implementations
- native java code that allows operations on the android Sqlite database
- Since Sqlite has a very similar syntax to Mysql we were able to use the same Sql which is used on the server for searching with minimal changes.
- Since Sqlite has a very similar syntax to Mysql we were able to use the same Sql which is used on the server for searching with minimal changes.
- javascript code for operations on a lovefield database, which is a relational database wrapper over indexedDb, used by the chrome app
- Lovefield can be manipulated using a javascipt API and uses a builder syntax to construct sql statements link. The Sql used by the server has been ported to this builder format.
- The server search Sql makes use of the sql group_concat function along with a paged result for high performance infinite scrolling of the search results. The group_concat is not supported in lovefield. To get around this limitation while still maintaining the performance of the infinite scroll the search query has been split into 2 seperate queries. This had to be done because the group_concat allows us to get the correct number of results along with all their attribute data that is required for the registration page search.
Visits and Encounters
Existing approach for online
VISIT :
Visits are used to denote a patient’s entry into the hospital and a visit stays open for as long as the patient is in the hospital. The duration of a visit is configurable and can be set to different durations (like 24 hours or 48 hours).
Capturing and storing visits have other benefits :
- It can be used in reporting where you count visits by different types.
- It can be used to configure queues in other apps such as Clinical or Radiology. For Eg. Patients with an open visit of type IPD will appear in the IPD tab (IPD patient queue) or patients with an open visit of type OPD will appear in the OPD patient queue.
During a visit to a hospital a patient can go through various consultations in different departments. These are tracked via encounters that are logged under a visit.
A visit is started for the patient from the registration page. This could be while a new patient is being registered or when an already registered patient is searched for. In both cases, the start of a visit would indicate the beginning of a patient’s process in the hospital.
ENCOUNTER :
When a patient visits a hospital, they might have to be treated in various departments by different doctors. Each of these incidents is called an “Encounter”. Encounters can be used to denote locations such as an Lab, Pharmacy or actions such as Admissions, Discharges etc.
Encounter types are currently defined and maintained in OpenMRS.
When a patient is registered, a registration encounter is created. When some clinical data is recorded for the patient and saved, a clinical encounter is created for the patient. Such encounters can be defined depending on the needs of the hospital where the application is installed.
A visit can have multiple encounters associated with it depending on the actions performed or the locations visited by the patient in the hospital during that particular visit.
Approach for offline
Functionally, visits and encounters are handled similar to how they are handled in online mode with some differences as listed below:
A visit is not opened for a patient during registration. Patient registration information is saved on the device and even when synced, no visit is created for the patient. The same is the case of encounters in that no registration encounter is created for a patient after registration.
When clinical data (observations) is recorded for a patient and saved when offline, a dummy visit and an encounter are opened and stored on the device. There are three scenarios:
- A new patient created on offline device
- Clinical data added for existing patients
- Clinical data added for a patient when offline, but before sync the patient also has a open visit in hospital.
When the clinical shows the visits, there are scenarios where last n visits are requested. For offline, the last n visits are shown plus any information from the dummy visit (if any) are shown.
The scenarios are discussed in detail below.
1 - A new patient created on offline device
2 - Clinical data added for existing patients
3 - Clinical data added for a patient when offline, but before sync the patient also has a open visit in hospital.
Configuration of Visit Matcher For Offline:
A global property is added to openmrs to set visit matcher to Offline Visit matcher.
Configuration of Recent Patients in Clinical Search All Tab for Bahmni Connect
The All Tab on page load shows a list of patient below the search bar that have been created or have an encounter in the last 14 days.
The duration for the recent patient list can be configured in the clinical/app.json file in the config section
{ "config": { "recentPatientsDuration": 7 } }
Hiding Clinical Search Tabs for Bahmni Connect
Configured patient search tabs in the Clinical app can be hidden on Bahmni Connect by specifying an additional flag "offline:false" in the search tab configuration block in clinical/extension.json
"bahmni_clinical_patients_search_allpatients_active_app:clinical": { "id": "bahmni.clinical.patients.search.activePatients", "extensionPointId": "org.bahmni.patient.search", "type": "config", "extensionParams": { "searchHandler": "emrapi.sqlSearch.activePatients", "translationKey": "Active", "forwardUrl": "#/default/patient/{{patientUuid}}/dashboard" }, "label": "Active", "offline": false, "order": 2, "requiredPrivilege": "app:clinical" },
Video walkthrough on YouTube of the Bahmni Connect App:
The Bahmni documentation is licensed under Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)