Isso não funciona porque source é um comando de shell, então ExecStart= ou ExecStartPre= do systemd não os entenderá diretamente ... (BTW, o mesmo vale para cd e o && .)
Você poderia alcançar isso executando um shell explicitamente e executando todos os seus comandos juntos:
ExecStart=/bin/sh -c 'cd /home/debian/ap/ && source venv-ap/bin/activate && crossbar start'
Mas uma abordagem melhor é, em vez de pesquisar o script "activate", usar o executável python no bin/ de seu virtualenv diretamente.
Se você olhar para o documento de uso do virtualenv, verá que ele diz:
ENV/binis created, where executables live - noticeably a new python. Thus running a script with#! /path/to/ENV/bin/pythonwould run that script under this virtualenv’s python.
Em outras palavras, assumindo que crossbar é o script Python que você deseja executar que requer o venv-ap virtualenv, simplesmente inicie crossbar com:
#!/home/debian/ap/venv-ap/bin/python
E ele usará automaticamente o virtualenv sempre que for chamado.
Também é possível invocar o interpretador Python do virtualenv diretamente, com:
ExecStart=/home/debian/ap/venv-ap/bin/python /path/to/crossbar start
(Além disso, com relação à execução em um diretório específico, definir WorkingDirectory=/home/debian/ap é melhor do que usar o comando cd . Você não precisa de um shell dessa maneira e o systemd pode fazer melhor tratamento de erros para você.)