diff --git a/Dockerfile b/Dockerfile index f26eea7..8db341c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN cd /src/msg-core && mkdir build && cd build && cmake .. && make && make inst RUN cd /src/phevcore && mkdir build && cd build && cmake .. && make && make install COPY . /src/phevctl WORKDIR /src/phevctl -RUN mkdir -p build && cd build && cmake .. && make +RUN mkdir -p build && cd build && cmake .. && make ENTRYPOINT ["/src/phevctl/build/phevctl"] CMD [] diff --git a/README.md b/README.md index 0ce63e7..79fffc7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This is a command line interface developed to control the Mitsubish Outlander PHEV via the WiFi interface. It uses the phev library found [here](https://github.com/phev-remote/phevcore). -**Version 0.1** +**Version 0.1** **Updates** ECU 0.3.0.0 version now supported (Long password version MY18) @@ -80,7 +80,7 @@ Server: Docker Engine - Community Version: 0.18.0 GitCommit: fec3683 ``` -Check out this repository by cloning +Check out this repository by cloning ``` git clone https://github.com/phev-remote/phevctl ``` @@ -95,12 +95,20 @@ docker run /phevctl --help ``` You should see the following help. ``` -Mitsubishi Outlander PHEV Remote CLI - Designed and coded by Jamie Nuttall 2019 - Usage: phevctl [OPTION...] register or: phevctl [OPTION...] battery + or: phevctl [OPTION...] chargestatus + or: phevctl [OPTION...] lockstatus + or: phevctl [OPTION...] hvac + or: phevctl [OPTION...] remaningchargestatus + or: phevctl [OPTION...] update or: phevctl [OPTION...] aircon [on|off] + or: phevctl [OPTION...] acmode [heat|cool|windscreen] [10|20|30] + or: phevctl [OPTION...] --car-model=2019 acmode [heat|cool|windscreen] [10|20|30] or: phevctl [OPTION...] headlights [on|off] + or: phevctl [OPTION...] parkinglights [on|off] + or: phevctl [OPTION...] monitor + or: phevctl [OPTION...] get Program to control the car via the remote WiFi interface. Requires this device @@ -110,11 +118,11 @@ is on the 192.168.8.x subnet. THIS PROGRAM COMES WITH NO WARRANTY ANY DAMAGE TO THE CAR OR ANY OTHER EQUIPMENT IS AT THE USERS OWN RISK. + -c, --car-model= Model Year. -m, --mac= MAC address. -v, --verbose Verbose output -?, --help Give this help list --usage Give a short usage message - -V, --version Print program version Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options. @@ -132,13 +140,13 @@ Locate your Wi-Fi details and you should have a line that says your IP address. ### Windows command prompt ``` -ipconfig +ipconfig ... IPv4 Address. . . . . . . . . . . : 192.168.8.47 ``` ### Linux ``` -ifconfig -a +ifconfig -a ... wlan0: inet 192.168.8.47 @@ -146,7 +154,7 @@ wlan0: ## Registering your device -As in with the official app the device needs to be registered with the car. +As in with the official app the device needs to be registered with the car. Firstly put your car into registration mode instructions [here](https://www.mitsubishi-motors.com/en/products/outlander_phev/app/remote/jizen.html) @@ -158,10 +166,19 @@ You should see the message that the car is now registered. ## Using commands You can then follow the help instructions to get the battery level and switch on and off the air conditioning and head lights. ``` + docker run papawattu/phevctl battery docker run papawattu/phevctl aircon on docker run papawattu/phevctl headlights on + +docker run papawattu/phevctl chargestatus +docker run papawattu/phevctl lockstatus +docker run papawattu/phevctl hvac +docker run papawattu/phevctl remaningchargestatus +docker run papawattu/phevctl update +docker run papawattu/phevctl --car-model=2019 acmode heat 20 + ``` -Have fun!!! +Have fun!!! diff --git a/include/phevargs.h b/include/phevargs.h index 03ec7e6..d5e08b2 100644 --- a/include/phevargs.h +++ b/include/phevargs.h @@ -13,8 +13,14 @@ #define HEADLIGHTS "headlights" #define PARKING_LIGHTS "parkinglights" #define BATTERY "battery" +#define ISLOCKED "lockstatus" +#define CHARGING_STATUS "chargestatus" +#define HVAC_STATUS "hvac" +#define UPDATE "update" +#define REMAINING_CHARGING_STATUS "remaningchargestatus" #define AIRCON "aircon" #define AIRCON_MODE "acmode" +#define TEST_MODE "test" #define REGISTER "register" #define MONITOR "monitor" #define GET "get" @@ -34,7 +40,14 @@ typedef enum phev_args_commands_t { CMD_HEADLIGHTS, CMD_PARKING_LIGHTS, CMD_BATTERY, + CMD_ISLOCKED, + CMD_CHARGING_STATUS, + CMD_HVAC_STATUS, + CMD_REMAINING_CHARGING_STATUS, CMD_AIRCON, + CMD_PANIC, + CMD_HORN, + CMD_UPDATE, CMD_AIRCON_MODE, CMD_GET_REG_VAL, CMD_DISPLAY_REG, @@ -49,6 +62,7 @@ typedef struct phev_args_opts_t { char * topic; char * command_topic; bool verbose; + int carModel; bool operand_on; uint8_t operand_mode; uint8_t operand_time; @@ -64,13 +78,14 @@ static uint8_t PHEV_ARGS_DEFAULT_MAC[] = {0,0,0,0,0,0}; static const char * phev_args_argp_program_version = "Version\t" VERSION; static const char * phev_args_argp_program_bug_address = "jamie@wattu.com"; static char phev_args_doc[] = "\n\nProgram to control the car via the remote WiFi interface. Requires this device to be connected to the REMOTE**** access point with a valid IP address, which is on the 192.168.8.x subnet.\n\nTHIS PROGRAM COMES WITH NO WARRANTY ANY DAMAGE TO THE CAR OR ANY OTHER EQUIPMENT IS AT THE USERS OWN RISK."; -static char phev_args_args_doc[] = "register\nbattery\naircon [on|off]\nacmode [heat|cool|windscreen] [10|20|30]\nheadlights [on|off]\nparkinglights [on|off]\nmonitor\nget "; -static struct argp_option phev_args_options[] = { +static char phev_args_args_doc[] = "register\nbattery\nchargestatus\nlockstatus\nhvac\nremaningchargestatus\nupdate\naircon [on|off]\nacmode [heat|cool|windscreen] [10|20|30]\nheadlights [on|off]\nparkinglights [on|off]\nmonitor\nget "; +static struct argp_option phev_args_options[] = { { "mac", 'm', "",0, "MAC address."}, + { "car-model", 'c', "",0, "Model Year."}, { "host", 'h', "",OPTION_HIDDEN, "IP address of car - defaults to 192.168.8.46."}, { "port", 'p', "",OPTION_HIDDEN, "Port to use - defaults to 8080"}, { "verbose",'v',0,0,"Verbose output"}, - { 0 } + { 0 } }; phev_args_opts_t * phev_args_parse(int argc, char *argv[]); diff --git a/main.c b/main.c index 42acfe0..1cf0fca 100644 --- a/main.c +++ b/main.c @@ -72,6 +72,67 @@ static int main_eventHandler(phevEvent_t *event) } break; } + case CMD_ISLOCKED: + { + if (event->reg == KO_WF_DOOR_STATUS_INFO_REP_EVR) + { + int islocked = phev_isLocked(ctx); + if (islocked < 0) + { + printf("Doors in UNKNOWN STATE\n"); + } else if (islocked == 1){ + printf("Doors are Locked\n"); + } else{ + printf("Doors are UnLocked\n"); + } + exit(0); + } + break; + } + case CMD_CHARGING_STATUS: + { + if (event->reg == KO_WF_OBCHG_OK_ON_INFO_REP_EVR) + { + int chargeStatus = phev_chargingStatus(ctx); + if (chargeStatus < 0) + { + return 0; + } + if (chargeStatus == 1) + { + printf("Charging...\n"); + } else { + printf("Not charging\n"); + } + exit(0); + } + break; + } + case CMD_HVAC_STATUS: + { + if (event->reg == KO_WF_TM_AC_STAT_INFO_REP_EVR) + { + phevServiceHVAC_t * ph = phev_HVACStatus(ctx); + printf("Operating:%d\n", ph->operating); + printf("mode:%d\n", ph->mode); + exit(0); + } + break; + } + case CMD_REMAINING_CHARGING_STATUS: + { + if (event->reg == KO_WF_OBCHG_OK_ON_INFO_REP_EVR) + { + int remainingChargeStatus = phev_remainingChargeTime(ctx); + if (remainingChargeStatus < 0) + { + return 0; + } + printf("Remaining %d\n", remainingChargeStatus); + exit(0); + } + break; + } case CMD_DISPLAY_REG: { printf("Register : %d Data :", event->reg); @@ -150,10 +211,25 @@ static int main_eventHandler(phevEvent_t *event) phev_airCon(event->ctx, opts->operand_on, operationCallback); break; } + case CMD_UPDATE: + { + printf("Update All\n"); + phev_updateAll(event->ctx, operationCallback); + break; + } case CMD_AIRCON_MODE: { printf("Switching air conditioning mode to %d for %d mins\n", opts->operand_mode, opts->operand_time); - phev_airConMode(event->ctx, opts->operand_mode, opts->operand_time, operationCallback); + if (opts->verbose) + { + printf("Car Model: %d\n", opts->carModel); + } + if ( opts->carModel == 2019){ + phev_airConMY19(event->ctx, opts->operand_mode, opts->operand_time, operationCallback); + } else { + phev_airConMode(event->ctx, opts->operand_mode, opts->operand_time, operationCallback); + } + break; } } @@ -253,7 +329,7 @@ int main(int argc, char *argv[]) switch(ch) { - case 'r': + case 'r': { printf("Disconnecting\n"); phev_disconnect(ctx); diff --git a/src/phevargs.c b/src/phevargs.c index afcef43..d3a0227 100644 --- a/src/phevargs.c +++ b/src/phevargs.c @@ -7,7 +7,7 @@ int phev_args_validate(int arg_num,phev_args_opts_t * opts) { case CMD_HEADLIGHTS: case CMD_PARKING_LIGHTS: - case CMD_AIRCON: + case CMD_AIRCON: { if(arg_num == 2) { @@ -39,7 +39,33 @@ int phev_args_validate(int arg_num,phev_args_opts_t * opts) } break; } + case CMD_UPDATE: case CMD_BATTERY: + case CMD_ISLOCKED: + { + if(arg_num == 1) + { + return 0; + } + break; + } + case CMD_CHARGING_STATUS: + { + if(arg_num == 1) + { + return 0; + } + break; + } + case CMD_HVAC_STATUS: + { + if(arg_num == 1) + { + return 0; + } + break; + } + case CMD_REMAINING_CHARGING_STATUS: { if(arg_num == 1) { @@ -79,7 +105,7 @@ int phev_args_process_operands(char * arg, int arg_num, phev_args_opts_t * opts) { opts->operand_on = true; break; - } + } if(strcmp(arg,OFF) == 0) { opts->operand_on = false; @@ -89,7 +115,7 @@ int phev_args_process_operands(char * arg, int arg_num, phev_args_opts_t * opts) opts->error_message = "Operand must be on or off"; break; } - + opts->error = true; opts->error_message = "Too many operands"; break; @@ -116,14 +142,14 @@ int phev_args_process_operands(char * arg, int arg_num, phev_args_opts_t * opts) opts->error = true; opts->error_message = "Unrecognised operand"; break; - } - + } + if(arg_num == 2) { if(strlen(arg) == 2 && isdigit(arg[0]) && isdigit(arg[1])) { opts->operand_time = atoi(arg); - + if(opts->operand_time != 10 && opts->operand_time != 20 && opts->operand_time != 30 @@ -131,23 +157,23 @@ int phev_args_process_operands(char * arg, int arg_num, phev_args_opts_t * opts) { opts->error = true; opts->error_message = "Unrecognised operand"; - break; + break; } - } - else + } + else { opts->error = true; opts->error_message = "Unrecognised operand"; } } - break; + break; } case CMD_GET_REG_VAL: { if(strlen(arg) == 2 && isdigit(arg[0]) && isdigit(arg[1]) && arg_num == 1) { opts->reg_operand = atoi(arg); - } - else + } + else { opts->error = true; opts->error_message = "Not a number"; @@ -155,6 +181,10 @@ int phev_args_process_operands(char * arg, int arg_num, phev_args_opts_t * opts) break; } case CMD_MONITOR: + case CMD_CHARGING_STATUS: + case CMD_HVAC_STATUS: + case CMD_ISLOCKED: + case CMD_REMAINING_CHARGING_STATUS: case CMD_BATTERY: { break; } @@ -180,10 +210,30 @@ int phev_args_process_command(char * arg, int arg_num, phev_args_opts_t * opts) { opts->command = CMD_BATTERY; } + if(strcmp(arg,ISLOCKED) == 0 && arg_num == 0) + { + opts->command = CMD_ISLOCKED; + } + if(strcmp(arg,CHARGING_STATUS) == 0 && arg_num == 0) + { + opts->command = CMD_CHARGING_STATUS; + } + if(strcmp(arg,REMAINING_CHARGING_STATUS) == 0 && arg_num == 0) + { + opts->command = CMD_REMAINING_CHARGING_STATUS; + } + if(strcmp(arg,HVAC_STATUS) == 0 && arg_num == 0) + { + opts->command = CMD_HVAC_STATUS; + } if(strcmp(arg,AIRCON) == 0 && arg_num == 0) { opts->command = CMD_AIRCON; } + if(strcmp(arg,UPDATE) == 0 && arg_num == 0) + { + opts->command = CMD_UPDATE; + } if(strcmp(arg,GET) == 0 && arg_num == 0) { opts->command = CMD_GET_REG_VAL; @@ -244,9 +294,9 @@ static error_t phev_args_parse_opt(int key, char *arg, struct argp_state *state) } opts->mac = PHEV_ARGS_DEFAULT_MAC; break; - } + } case 'h': { - if(arg !=NULL) + if(arg !=NULL) { opts->host = strdup(arg); } @@ -263,6 +313,10 @@ static error_t phev_args_parse_opt(int key, char *arg, struct argp_state *state) opts->verbose = true; break; } + case 'c': { + opts->carModel = atoi(arg); + break; + } case ARGP_KEY_END: { if(opts->error) @@ -276,7 +330,7 @@ static error_t phev_args_parse_opt(int key, char *arg, struct argp_state *state) opts->command = CMD_INVALID; printf("\nERROR : %s\n",opts->error_message); argp_usage(state); - } + } break; } case ARGP_KEY_ARG: { @@ -288,16 +342,16 @@ static error_t phev_args_parse_opt(int key, char *arg, struct argp_state *state) } break; } - + if(phev_args_process_operands(strdup(arg), state->arg_num,opts)) { opts->command = CMD_INVALID; } break; } - + default: return ARGP_ERR_UNKNOWN; - } + } return 0; } @@ -320,6 +374,6 @@ phev_args_opts_t * phev_args_parse(int argc, char *argv[]) arguments->error_message = ""; argp_parse(&phev_args_argp, argc, argv, 0, 0, arguments); - + return arguments; }