<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Neural Network demo
Start a Mosquitto container first. For example
Step1:  List of neurons
Step2:  Start client
Step3:  Utility functions
Step4:  Reset neurons
Step5:  Probe neurons by blinking LEDs
Step6:  Setup connections / weights / thresholds
Step7:  Stop the demo
<ASSISTANT_TASK:>
Python Code:
import os
import sys
import time
 
sys.path.append(os.path.abspath(os.path.join(os.path.pardir, os.path.sep.join(['..', 'codes']), 'client')))
sys.path.append(os.path.abspath(os.path.join(os.path.pardir, os.path.sep.join(['..', 'codes']), 'node')))
sys.path.append(os.path.abspath(os.path.join(os.path.pardir, os.path.sep.join(['..', 'codes']), 'shared')))
sys.path.append(os.path.abspath(os.path.join(os.path.pardir, os.path.sep.join(['..', 'codes']), 'micropython')))
 
import client
from collections import OrderedDict
import pandas as pd
from pandas import DataFrame
from time import sleep
REFRACTORY_PERIOD = 0.1   # 0.1 seconds
Explanation: Neural Network demo
Start a Mosquitto container first. For example:
- Use codes\_demo\1_start_broker.sh to start a Mosquitto container on Raspberry Pi.
- Config files are in mqtt_config\mqtt.
- set allow_anonymous true in mqtt_config\mqtt\config\mosquitto.conf to allow anonymous client.
Getting Started
What this notebook does:
- Using:
 - a client on PC
 - 6 ESP8266 modules (NodeMCU and D1 mini) as remote nodes
- List connected nodes
- Rename remote nodes
- Setup neural network configuration (connections, weights, thresholds)
- Fire up neurons and get logs.
End of explanation
neurons = ['n_Alpha', 'n_Beta', 'n_Lambda'] 
# neurons = ['n_Alpha']
neurons
Explanation: List of neurons
End of explanation
the_client = client.Client()
the_client.start()
while not the_client.status['Is connected']:            
    time.sleep(1)
    print('Node not ready yet.')
Explanation: Start client
End of explanation
# # Ask Hub for a list of connected nodes
# def list_nodes():
#     the_client.node.worker.roll_call()
#     time.sleep(2)
#     remote_nodes = sorted(the_client.node.worker.contacts.keys())
#     print('\n[____________ Connected nodes ____________]\n')
#     print('\nConnected nodes:\n{}\n'.format(remote_nodes))
        
#     return remote_nodes
def reset_node(node):
    message = {'message_type': 'exec',
               'to_exec': 'import machine;machine.reset()'}
    the_client.request(node, message) 
def fire(node):
    message = {'message_type': 'function',
               'function': 'fire'}
    the_client.request(node, message) 
def addConnection(node, neuron):
    message = {'message_type': 'function',
               'function': 'addConnection',
               'kwargs': {'neuron_id': neuron}}
    the_client.request(node, message) 
    
def set_connections(node, connections):
    message = {'message_type': 'function',
               'function': 'setConnections',
               'kwargs': {'connections': connections}}
    the_client.request(node, message)     
    
def get_connections(node):
    message = {'message_type': 'function',
               'function': 'getConnections', 
               'need_result': True}
    _, result = the_client.request(node, message) 
    return result.get()    
def setWeight(node, neuron, weight):
    message = {'message_type': 'function',
               'function': 'setWeight',
               'kwargs': {'neuron_id': neuron,
                          'weight': weight,}}
    the_client.request(node, message) 
def setThreshold(node, threshold):
    message = {'message_type': 'function',
               'function': 'setThreshold',
               'kwargs': {'threshold': threshold}}
    the_client.request(node, message) 
        
def getConfig(node):
    message = {'message_type': 'function',
               'function': 'getConfig', 
               'need_result': True}
    _, result = the_client.request(node, message) 
    return result.get()
def getLog(node):
    message = {'message_type': 'function',
               'function': 'getLog', 
               'need_result': True}
    _, result = the_client.request(node, message) 
    return result.get()
def emptyLog(node):
    message = {'message_type': 'function',
               'function': 'emptyLog'}
    the_client.request(node, message)
    
def emptyLogs():
    for neuron in neurons:
        emptyLog(neuron)
        
def mergeLogs():
    logs = []
    
    for neuron in neurons:
        if neuron != the_client.node.worker.name:  # exclude client self
            currentLog = getLog(neuron)
            if currentLog:
                logs += currentLog 
            
    df = DataFrame(list(logs), columns = ['time', 'neuron', 'message']) 
    df.set_index('time', inplace = True)
    df.sort_index(inplace = True)
    
    return df        
def printConfig(neuron):
    print('{0:_^78}\n {1}\n'.format(neuron + " config:", getConfig(neuron)))
Explanation: Utility functions
End of explanation
# reset_node('Hub');
Explanation: Reset neurons
End of explanation
messages = {}
messages['blink_led'] = {'message_type': 'command',
                         'command': 'blink led',
                         'kwargs': {'times': 3, 'on_seconds': 0.1, 'off_seconds': 0.1}}
the_client.request('Hub', messages['blink_led']);
Explanation: Probe neurons by blinking LEDs
End of explanation
addConnection('n_Alpha', 'n_Lambda');
addConnection('n_Beta', 'n_Lambda');
setWeight('n_Lambda', 'n_Alpha', 1); 
setWeight('n_Lambda', 'n_Beta', 1);
setThreshold('n_Lambda', 2.8);  # input enough to trigger Lambda
fire('n_Alpha');
fire('n_Beta');
setThreshold('n_Lambda', 2.8);  # input not enough to trigger Lambda
fire('n_Alpha');
fire('n_Beta');
setThreshold('n_Lambda', 1.8);  # input not enough to trigger Lambda
fire('n_Alpha'); 
setThreshold('n_Lambda', 1.8);  # input enough to trigger Lambda
fire('n_Alpha');
fire('n_Beta');
# setThreshold('n_Lambda', 1.8);
# emptyLogs()
# sleep(REFRACTORY_PERIOD)
# fire('n_Alpha')
# fire('n_Beta') 
# sleep(2)
# mergeLogs()
# for neuron in reversed(neurons): printConfig(neuron)
Explanation: Setup connections / weights / thresholds
End of explanation
# Stopping
the_client.stop()
the_client = None
print ('\n[________________ Demo stopped ________________]\n')
Explanation: Stop the demo
End of explanation
<END_TASK>