Repository: missionpinball/mpf
Issue: Fix encoding error in BCP

It seems as "#" in a string currently breaks bcp. Properly encode and decode that.

```
2020-01-26 09:51:54,111 : MPF-MC BCP Server : DECODE BCP ERROR. Message: trigger?json={"name": "slides_play", "settings": {"high_score_enter_initials": {"target": null, "background_color": [0.0, 0.0, 0.0, 1.0], "priority": null, "show": true, "force": false, "expire": null, "slide": null, "tokens": {}, "action": "play"}}, "context": "high_score", "calling_context": "high_score_enter_initials", "priority": 1600, "award": "HIGH SCORE #2", "player_num": 1, "value": 81120}
2020-01-26 09:51:54,561 : mpfmc : Shutting down due to child thread crash
2020-01-26 09:51:54,561 : mpfmc : Crash details: Traceback (most recent call last):
  File "c:\\users\\andrew\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\mpfmc\\core\\bcp_server.py", line 156, in run
    self._process_receives_messages(commands)
  File "c:\\users\\andrew\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\mpfmc\\core\\bcp_server.py", line 186, in _process_receives_messages
    self.process_received_message(decoded_cmd)
  File "c:\\users\\andrew\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\mpfmc\\core\\bcp_server.py", line 247, in process_received_message
    cmd, kwargs = bcp.decode_command_string(message)
  File "c:\\users\\andrew\\appdata\\local\\programs\\python\\python36\\lib\\site-packages\\mpf\\core\\bcp\\bcp_socket_client.py", line 45, in decode_command_string
    kwargs = json.loads(bcp_command.query[5:])
  File "c:\\users\\andrew\\appdata\\local\\programs\\python\\python36\\lib\\json\\__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "c:\\users\\andrew\\appdata\\local\\programs\\python\\python36\\lib\\json\\decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "c:\\users\\andrew\\appdata\\local\\programs\\python\\python36\\lib\\json\\decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 339 (char 338)
```

Changed files:
mpf/tests/test_BcpSocketClient.py, mpf/core/bcp/bcp_socket_client.py

diff --git a/mpf/core/bcp/bcp_socket_client.py b/mpf/core/bcp/bcp_socket_client.py
index e89e64704..0fad15c65 100644
--- a/mpf/core/bcp/bcp_socket_client.py
+++ b/mpf/core/bcp/bcp_socket_client.py
@@ -39,7 +39,7 @@ def decode_command_string(bcp_string) -> Tuple[str, dict]:
     will be preserved.
 
     """
-    bcp_command = urlsplit(bcp_string)
+    bcp_command = urlsplit(bcp_string, allow_fragments=False)
 
     if bcp_command.query[0:5] == "json=":
         kwargs = json.loads(bcp_command.query[5:])
diff --git a/mpf/tests/test_BcpSocketClient.py b/mpf/tests/test_BcpSocketClient.py
index 6f63e2b0c..3ea65476a 100644
--- a/mpf/tests/test_BcpSocketClient.py
+++ b/mpf/tests/test_BcpSocketClient.py
@@ -108,6 +108,20 @@ class TestBcpSocketClientEncoding(unittest.TestCase):
         self.assertEqual(decoded_dict['dict2'][1],
                          dict(key3='value5', key4='value6'))
 
+    def test_json_encoding_decoding_with_hashtags(self):
+        # see: https://github.com/missionpinball/mpf/issues/1495
+        command = 'play'
+        kwargs = dict()
+        kwargs['dict1'] = dict(key1='value1 #', key2='value2 #')
+
+        encoded_string = encode_command_string(command, **kwargs)
+        decoded_command, decoded_dict = decode_command_string(encoded_string)
+
+        self.assertEqual('play', decoded_command)
+        self.assertIn('dict1', decoded_dict)
+        self.assertEqual(decoded_dict['dict1']['key1'], 'value1 #')
+        self.assertEqual(decoded_dict['dict1']['key2'], 'value2 #')
+
 
 class MockBcpQueueSocket(MockQueueSocket):